Properly check for all needed extensions and handle gracefully absence.

svn path=/trunk/KDE/kdebase/workspace/; revision=669827
This commit is contained in:
Luboš Luňák 2007-05-30 14:22:09 +00:00
parent eb4fb38657
commit 1caa3f95ed
13 changed files with 210 additions and 79 deletions

View file

@ -480,7 +480,7 @@ void Client::updateShape()
// !shape() mask setting is done in setMask() when the decoration
// calls it or when the decoration is created/destroyed
if( Extensions::shapeVersion() >= 0x11 ) // 1.1, has input shape support
if( Extensions::shapeInputAvailable())
{ // There appears to be no way to find out if a window has input
// shape set or not, so always propagate the input shape
// (it's the same like the bounding shape by default).

View file

@ -25,6 +25,8 @@ License. See the file "COPYING" for the exact licensing terms.
*/
#include <config-X11.h>
#include "utils.h"
#include "workspace.h"
#include "client.h"
@ -43,6 +45,16 @@ License. See the file "COPYING" for the exact licensing terms.
#include <X11/extensions/shape.h>
#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
#if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3
#define HAVE_XCOMPOSITE_OVERLAY
#endif
#endif
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
namespace KWin
{
@ -78,25 +90,32 @@ void Workspace::setupCompositing()
switch( type )
{
case 'B':
scene = new SceneBasic( this );
kDebug( 1212 ) << "X compositing" << endl;
scene = new SceneBasic( this );
break;
#if defined(HAVE_XRENDER) && defined(HAVE_XFIXES)
case 'X':
scene = new SceneXrender( this );
kDebug( 1212 ) << "XRender compositing" << endl;
scene = new SceneXrender( this );
break;
#endif
#ifdef HAVE_OPENGL
case 'O':
scene = new SceneOpenGL( this );
kDebug( 1212 ) << "OpenGL compositing" << endl;
scene = new SceneOpenGL( this );
break;
#endif
default:
kDebug( 1212 ) << "No compositing" << endl;
return;
}
if( scene != NULL && scene->initFailed())
{
delete scene;
scene = NULL;
delete cm_selection;
return;
}
int rate = 0;
if( options->refreshRate > 0 )
{ // use manually configured refresh rate

View file

@ -15,6 +15,8 @@ License. See the file "COPYING" for the exact licensing terms.
*/
#include <config-X11.h>
#include "client.h"
#include "workspace.h"
#include "atoms.h"
@ -34,6 +36,10 @@ License. See the file "COPYING" for the exact licensing terms.
#include <X11/Xatom.h>
#include <QX11Info>
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
namespace KWin
{

View file

@ -33,6 +33,8 @@ class Scene
virtual ~Scene() = 0;
class Window;
// Returns true if the ctor failed to properly initialize.
virtual bool initFailed() const = 0;
virtual CompositingType compositingType() const = 0;
// Repaints the given screen areas, windows provides the stacking order.
// The entry point for the main part of the painting pass.

View file

@ -60,6 +60,11 @@ void SceneBasic::paint( QRegion, ToplevelList windows )
XFlush( display());
}
bool SceneBasic::initFailed() const
{
return false;
}
// These functions are not used at all, SceneBasic
// is not using inherited functionality.

View file

@ -22,6 +22,7 @@ class SceneBasic
public:
SceneBasic( Workspace* ws );
virtual ~SceneBasic();
virtual bool initFailed() const;
virtual CompositingType compositingType() const { return NoCompositing; }
virtual void paint( QRegion damage, ToplevelList windows );
protected:

View file

@ -85,8 +85,8 @@ SceneOpenGL::FBConfigInfo SceneOpenGL::fbcdrawableinfo[ 32 + 1 ];
GLXContext SceneOpenGL::ctxbuffer;
GLXContext SceneOpenGL::ctxdrawable;
// the destination drawable where the compositing is done
GLXDrawable SceneOpenGL::glxbuffer;
GLXDrawable SceneOpenGL::last_pixmap;
GLXDrawable SceneOpenGL::glxbuffer = None;
GLXDrawable SceneOpenGL::last_pixmap = None;
bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap)
bool SceneOpenGL::strict_binding; // intended for AIGLX
bool SceneOpenGL::db; // destination drawable is double-buffered
@ -99,20 +99,28 @@ XShmSegmentInfo SceneOpenGL::shm;
SceneOpenGL::SceneOpenGL( Workspace* ws )
: Scene( ws )
, init_ok( false )
{
// TODO add checks where needed
int dummy;
if( !glXQueryExtension( display(), &dummy, &dummy ))
return;
if( !Extensions::glxAvailable())
{
kDebug( 1212 ) << "No glx extensions available" << endl;
return; // error
}
initGLX();
// check for FBConfig support
if( !hasGLXVersion( 1, 3 ) && !hasGLExtension( "GLX_SGIX_fbconfig" ))
return;
{
kDebug( 1212 ) << "GLX1.3 or GLX_SGIX_fbconfig missing" << endl;
return; // error
}
strict_binding = false; // not needed now
selectMode();
initBuffer(); // create destination buffer
initRenderingContext();
if( !selectMode())
return; // error
if( !initBuffer()) // create destination buffer
return; // error
if( !initRenderingContext())
return; // error
// Initialize OpenGL
initGL();
if( db )
@ -141,10 +149,16 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
checkGLError( "Init" );
kDebug( 1212 ) << "DB:" << db << ", TFP:" << tfp_mode << ", SHM:" << shm_mode
<< ", Direct:" << bool( glXIsDirect( display(), ctxbuffer )) << endl;
init_ok = true;
}
SceneOpenGL::~SceneOpenGL()
{
if( !init_ok )
{
// TODO this probably needs to clean up whatever has been created until the failure
return;
}
foreach( Window* w, windows )
delete w;
// do cleanup after initBuffer()
@ -173,7 +187,12 @@ SceneOpenGL::~SceneOpenGL()
checkGLError( "Cleanup" );
}
void SceneOpenGL::selectMode()
bool SceneOpenGL::initFailed() const
{
return !init_ok;
}
bool SceneOpenGL::selectMode()
{
// select mode - try TFP first, then SHM, otherwise fallback mode
shm_mode = false;
@ -193,10 +212,11 @@ void SceneOpenGL::selectMode()
tfp_mode = true;
}
if( !initDrawableConfigs())
assert( false );
return false;
// use copy buffer hack from glcompmgr (called COPY_BUFFER there) - nvidia drivers older than
// 1.0-9xxx don't update pixmaps properly, so do a copy first
copy_buffer_hack = !tfp_mode && !shm_mode; // TODO detect that it's nvidia < 1.0-9xxx driver
return true;
}
bool SceneOpenGL::initTfp()
@ -258,7 +278,7 @@ void SceneOpenGL::cleanupShm()
#endif
}
void SceneOpenGL::initRenderingContext()
bool SceneOpenGL::initRenderingContext()
{
bool direct_rendering = options->glDirect;
if( !tfp_mode && !shm_mode )
@ -270,24 +290,26 @@ void SceneOpenGL::initRenderingContext()
|| errs.error( true ))
{ // failed
if( !direct_rendering )
assert( false );
return false;
glXDestroyContext( display(), ctxbuffer );
direct_rendering = false; // try again
ctxbuffer = glXCreateNewContext( display(), fbcbuffer, GLX_RGBA_TYPE, NULL, GL_FALSE );
if( ctxbuffer == NULL || !glXMakeContextCurrent( display(), glxbuffer, glxbuffer, ctxbuffer ))
assert( false );
return false;
}
if( !tfp_mode && !shm_mode )
{
ctxdrawable = glXCreateNewContext( display(), fbcdrawableinfo[ QX11Info::appDepth() ].fbconfig, GLX_RGBA_TYPE, ctxbuffer,
direct_rendering ? GL_TRUE : GL_FALSE );
}
return true;
}
// create destination buffer
void SceneOpenGL::initBuffer()
bool SceneOpenGL::initBuffer()
{
initBufferConfigs();
if( !initBufferConfigs())
return false;
if( fbcbuffer_db != NULL && wspace->createOverlay())
{ // we have overlay, try to create double-buffered window in it
fbcbuffer = fbcbuffer_db;
@ -316,7 +338,10 @@ void SceneOpenGL::initBuffer()
glxbuffer = glXCreatePixmap( display(), fbcbuffer, buffer, NULL );
}
else
assert( false );
{
return false; // error
}
return true;
}
// choose the best configs for the destination buffer

View file

@ -32,6 +32,7 @@ class SceneOpenGL
class Window;
SceneOpenGL( Workspace* ws );
virtual ~SceneOpenGL();
virtual bool initFailed() const;
virtual CompositingType compositingType() const { return OpenGLCompositing; }
virtual void paint( QRegion damage, ToplevelList windows );
virtual void windowGeometryShapeChanged( Toplevel* );
@ -43,12 +44,12 @@ class SceneOpenGL
virtual void paintGenericScreen( int mask, ScreenPaintData data );
virtual void paintBackground( QRegion region );
private:
void selectMode();
bool selectMode();
bool initTfp();
bool initShm();
void cleanupShm();
void initBuffer();
void initRenderingContext();
bool initBuffer();
bool initRenderingContext();
bool initBufferConfigs();
bool initDrawableConfigs();
void waitSync();
@ -80,6 +81,7 @@ class SceneOpenGL
#ifdef HAVE_XSHM
static XShmSegmentInfo shm;
#endif
bool init_ok;
};
class SceneOpenGL::Texture

View file

@ -70,14 +70,28 @@ kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
}
#endif
Picture SceneXrender::buffer;
Picture SceneXrender::buffer = None;
ScreenPaintData SceneXrender::screen_paint;
SceneXrender::SceneXrender( Workspace* ws )
: Scene( ws )
, front( None )
, init_ok( false )
{
if( !Extensions::renderAvailable())
{
kDebug( 1212 ) << "No xrender extension available" << endl;
return;
}
if( !Extensions::fixesRegionAvailable())
{
kDebug( 1212 ) << "No xfixes v3+ extension available" << endl;
return;
}
// create XRender picture for the root window
format = XRenderFindVisualFormat( display(), DefaultVisual( display(), DefaultScreen( display())));
if( format == NULL )
return; // error
if( wspace->createOverlay())
{
wspace->setupOverlay( None );
@ -90,10 +104,13 @@ SceneXrender::SceneXrender( Workspace* ws )
front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa );
}
createBuffer();
init_ok = true;
}
SceneXrender::~SceneXrender()
{
if( !init_ok )
return;
XRenderFreePicture( display(), front );
XRenderFreePicture( display(), buffer );
wspace->destroyOverlay();
@ -101,6 +118,22 @@ SceneXrender::~SceneXrender()
delete w;
}
bool SceneXrender::initFailed() const
{
return !init_ok;
}
// Create the compositing buffer. The root window is not double-buffered,
// so it is done manually using this buffer,
void SceneXrender::createBuffer()
{
if( buffer != None )
XRenderFreePicture( display(), buffer );
Pixmap pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), QX11Info::appDepth());
buffer = XRenderCreatePicture( display(), pixmap, format, 0, 0 );
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
}
// the entry point for painting
void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
{
@ -269,17 +302,6 @@ void SceneXrender::windowAdded( Toplevel* c )
windows[ c ] = new Window( c );
}
// Create the compositing buffer. The root window is not double-buffered,
// so it is done manually using this buffer,
void SceneXrender::createBuffer()
{
if( buffer != None )
XRenderFreePicture( display(), buffer );
Pixmap pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), QX11Info::appDepth());
buffer = XRenderCreatePicture( display(), pixmap, format, 0, 0 );
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
}
// Convert QRegion to XserverRegion. This code uses XserverRegion
// only when really necessary as the shared implementation uses
// QRegion.

View file

@ -29,6 +29,7 @@ class SceneXrender
public:
SceneXrender( Workspace* ws );
virtual ~SceneXrender();
virtual bool initFailed() const;
virtual CompositingType compositingType() const { return XRenderCompositing; }
virtual void paint( QRegion damage, ToplevelList windows );
virtual void windowGeometryShapeChanged( Toplevel* );
@ -50,6 +51,7 @@ class SceneXrender
static ScreenPaintData screen_paint;
class Window;
QHash< Toplevel*, Window* > windows;
bool init_ok;
};
class SceneXrender::Window

View file

@ -11,6 +11,8 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_TOPLEVEL_H
#define KWIN_TOPLEVEL_H
#include <config-X11.h>
#include <assert.h>
#include <qobject.h>
#include <kdecoration.h>
@ -18,6 +20,10 @@ License. See the file "COPYING" for the exact licensing terms.
#include "utils.h"
#include "workspace.h"
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
class NETWinInfo;
namespace KWin
@ -104,7 +110,9 @@ class Toplevel
void setWindowHandles( Window client, Window frame );
void detectShape( Window id );
virtual void propertyNotifyEvent( XPropertyEvent* e );
#ifdef HAVE_XDAMAGE
void damageNotifyEvent( XDamageNotifyEvent* e );
#endif
Pixmap createWindowPixmap();
void discardWindowPixmap();
void addDamage( const QRect& r );
@ -133,7 +141,9 @@ class Toplevel
Window frame;
Workspace* wspace;
Pixmap window_pix;
#ifdef HAVE_XDAMAGE
Damage damage_handle;
#endif
QRegion damage_region; // damage is really damaged window (XDamage) and texture needs
QRegion repaints_region; // updating, repaint just requires repaint of that area
bool is_shape;

View file

@ -32,6 +32,25 @@ License. See the file "COPYING" for the exact licensing terms.
#include <X11/Xatom.h>
#include <QX11Info>
#ifdef HAVE_XRENDER
#include <X11/extensions/Xrender.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
#endif
#ifdef HAVE_OPENGL
#include <GL/glx.h>
#endif
#include <stdio.h>
#include "atoms.h"
@ -51,9 +70,10 @@ bool Extensions::has_randr = false;
int Extensions::randr_event_base = 0;
bool Extensions::has_damage = false;
int Extensions::damage_event_base = 0;
bool Extensions::has_composite = false;
bool Extensions::has_composite_overlay = false;
bool Extensions::has_fixes = false;
int Extensions::composite_version = 0;
int Extensions::fixes_version = 0;
int Extensions::render_version = 0;
bool Extensions::has_glx = false;
void Extensions::init()
{
@ -81,24 +101,41 @@ void Extensions::init()
#else
has_damage = false;
#endif
composite_version = 0;
#ifdef HAVE_XCOMPOSITE
has_composite = XCompositeQueryExtension( display(), &dummy, &dummy );
if( has_composite )
if( XCompositeQueryExtension( display(), &dummy, &dummy ))
{
int major, minor;
int major = 0, minor = 0;
XCompositeQueryVersion( display(), &major, &minor );
has_composite = ( major > 0 || minor >= 2 );
has_composite_overlay = ( major > 0 || minor >= 3 );
composite_version = major * 0x10 + minor;
}
#else
has_composite = false;
has_composite_overlay = false;
#endif
fixes_version = 0;
#ifdef HAVE_XFIXES
has_fixes = XFixesQueryExtension( display(), &dummy, &dummy );
#else
has_fixes = false;
if( XFixesQueryExtension( display(), &dummy, &dummy ))
{
int major = 0, minor = 0;
XFixesQueryVersion( display(), &major, &minor );
fixes_version = major * 0x10 + minor;
}
#endif
render_version = 0;
#ifdef HAVE_XRENDER
if( XRenderQueryExtension( display(), &dummy, &dummy ))
{
int major = 0, minor = 0;
XRenderQueryVersion( display(), &major, &minor );
render_version = major * 0x10 + minor;
}
#endif
has_glx = false;
#ifdef HAVE_OPENGL
has_glx = glXQueryExtension( display(), &dummy, &dummy );
#endif
kDebug( 1212 ) << "Extensions: shape: 0x" << QString::number( shape_version, 16 )
<< " composite: 0x" << QString::number( composite_version, 16 )
<< " render: 0x" << QString::number( render_version, 16 )
<< " fixes: 0x" << QString::number( fixes_version, 16 ) << endl;
}
int Extensions::shapeNotifyEvent()
@ -120,6 +157,11 @@ bool Extensions::hasShape( Window w )
return boundingShaped != 0;
}
bool Extensions::shapeInputAvailable()
{
return shape_version >= 0x11; // 1.1
}
int Extensions::randrNotifyEvent()
{
#ifdef HAVE_XRANDR
@ -138,6 +180,16 @@ int Extensions::damageNotifyEvent()
#endif
}
bool Extensions::compositeOverlayAvailable()
{
return composite_version >= 0x03; // 0.3
}
bool Extensions::fixesRegionAvailable()
{
return fixes_version >= 0x30; // 3
}
void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
bool& minimize, bool& maximize, bool& close )
{

39
utils.h
View file

@ -18,25 +18,6 @@ License. See the file "COPYING" for the exact licensing terms.
#include <X11/Xlib.h>
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
#if XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR >= 3
#define HAVE_XCOMPOSITE_OVERLAY
#endif
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <fixx11h.h>
#include <QWidget>
@ -149,16 +130,19 @@ class Extensions
public:
static void init();
static bool shapeAvailable() { return shape_version > 0; }
static int shapeVersion() { return shape_version; } // as 16*major+minor, i.e. two hex digits
static bool shapeInputAvailable();
static int shapeNotifyEvent();
static bool hasShape( Window w );
static bool randrAvailable() { return has_randr; }
static int randrNotifyEvent();
static bool damageAvailable() { return has_damage; }
static int damageNotifyEvent();
static bool compositeAvailable() { return has_composite; }
static bool compositeOverlayAvailable() { return has_composite && has_composite_overlay; }
static bool fixesAvailable() { return has_fixes; }
static bool hasShape( Window w );
static bool compositeAvailable() { return composite_version > 0; }
static bool compositeOverlayAvailable();
static bool renderAvailable() { return render_version > 0; }
static bool fixesAvailable() { return fixes_version > 0; }
static bool fixesRegionAvailable();
static bool glxAvailable() { return has_glx; }
private:
static int shape_version;
static int shape_event_base;
@ -166,9 +150,10 @@ class Extensions
static int randr_event_base;
static bool has_damage;
static int damage_event_base;
static bool has_composite;
static bool has_composite_overlay;
static bool has_fixes;
static int composite_version;
static int render_version;
static int fixes_version;
static bool has_glx;
};
// compile with XShape older than 1.0