Change xrender code to match the opengl code.

Also dump the support for the current effect code, as that will
have to go anyway.


svn path=/branches/work/kwin_composite/; revision=595579
This commit is contained in:
Luboš Luňák 2006-10-14 22:08:51 +00:00
parent fef8c89b93
commit c7584b3bf8
2 changed files with 201 additions and 238 deletions

View file

@ -49,6 +49,9 @@ kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
} }
#endif #endif
Picture SceneXrender::buffer;
XserverRegion SceneXrender::infiniteRegion;
SceneXrender::SceneXrender( Workspace* ws ) SceneXrender::SceneXrender( Workspace* ws )
: Scene( ws ) : Scene( ws )
{ {
@ -56,6 +59,12 @@ SceneXrender::SceneXrender( Workspace* ws )
XRenderPictureAttributes pa; XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors; pa.subwindow_mode = IncludeInferiors;
front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa ); front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa );
XRectangle xr;
xr.x = SHRT_MIN / 2;
xr.y = SHRT_MIN / 2;
xr.width = SHRT_MAX;
xr.height = SHRT_MAX;
infiniteRegion = XFixesCreateRegion( display(), &xr, 1 );
createBuffer(); createBuffer();
} }
@ -63,18 +72,40 @@ SceneXrender::~SceneXrender()
{ {
XRenderFreePicture( display(), front ); XRenderFreePicture( display(), front );
XRenderFreePicture( display(), buffer ); XRenderFreePicture( display(), buffer );
for( QMap< Toplevel*, WindowData >::Iterator it = window_data.begin(); for( QMap< Toplevel*, Window >::Iterator it = windows.begin();
it != window_data.end(); it != windows.end();
++it ) ++it )
(*it).free(); (*it).free();
XFixesDestroyRegion( display(), infiniteRegion );
} }
void SceneXrender::paint( QRegion dam, ToplevelList windows ) void SceneXrender::paint( QRegion damage, ToplevelList windows )
{ {
#if 1 if( /*generic case*/ false )
dam = QRegion( 0, 0, displayWidth(), displayHeight()); paintGenericScreen( windows );
#endif else
QVector< QRect > rects = dam.rects(); paintSimpleScreen( damage, windows );
}
void SceneXrender::paintGenericScreen( ToplevelList windows )
{
paintBackground( infiniteRegion );
foreach( Toplevel* c, windows ) // bottom to top
{
assert( this->windows.contains( c ));
Window& w = this->windows[ c ];
if( !w.isVisible())
continue;
w.paint( infiniteRegion, PAINT_OPAQUE | PAINT_TRANSLUCENT );
}
// copy composed buffer to the root window
XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
XFlush( display());
}
void SceneXrender::paintSimpleScreen( QRegion damage, ToplevelList windows )
{
QVector< QRect > rects = damage.rects();
XRectangle* xr = new XRectangle[ rects.count() ]; XRectangle* xr = new XRectangle[ rects.count() ];
for( int i = 0; for( int i = 0;
i < rects.count(); i < rects.count();
@ -85,43 +116,11 @@ void SceneXrender::paint( QRegion dam, ToplevelList windows )
xr[ i ].width = rects[ i ].width(); xr[ i ].width = rects[ i ].width();
xr[ i ].height = rects[ i ].height(); xr[ i ].height = rects[ i ].height();
} }
XserverRegion damage = XFixesCreateRegion( display(), xr, rects.count()); XserverRegion region = XFixesCreateRegion( display(), xr, rects.count());
delete[] xr; delete[] xr;
// Use the damage region as the clip region for the root window // Use the damage region as the clip region for the root window
XFixesSetPictureClipRegion( display(), front, 0, 0, damage ); XFixesSetPictureClipRegion( display(), front, 0, 0, region );
// Prepare pass for windows QList< Phase2Data > phase2;
// Go top to bottom so that clipping is computed properly for phase1
for( int i = windows.count() - 1;
i >= 0;
--i )
{
Toplevel* c = windows[ i ];
resetWindowData( c );
WindowData& data = window_data[ c ];
Picture picture = data.picture();
if( picture == None ) // The render format can be null for GL and/or Xv visuals
{
windows.removeAt( i );
continue;
}
effects->transformWindow( c, data.matrix, data.effect ); // TODO remove, instead add initWindow() to effects
effects->transformWorkspace( data.matrix, data.effect );
data.saveClipRegion( damage );
if( data.simpleTransformation() && data.isOpaque())
{ // is opaque, has simple shape, can be clipped, will be painted using simpler faster method
// Subtract the clients shape from the damage region
XserverRegion shape = data.shape();
assert( shape != None );
XFixesSubtractRegion( display(), damage, damage, shape );
data.phase = 1;
}
else
data.phase = 2; // will be painted later bottom to top
}
// Fill any areas of the root window not covered by windows
XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage );
XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff };
XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
// Draw each opaque window top to bottom, subtracting the bounding rect of // Draw each opaque window top to bottom, subtracting the bounding rect of
// each window from the clip region after it's been drawn. // each window from the clip region after it's been drawn.
for( int i = windows.count() - 1; for( int i = windows.count() - 1;
@ -129,93 +128,77 @@ void SceneXrender::paint( QRegion dam, ToplevelList windows )
--i ) --i )
{ {
Toplevel* c = windows[ i ]; Toplevel* c = windows[ i ];
WindowData& data = window_data[ c ]; assert( this->windows.contains( c ));
if( data.phase != 1 ) Window& w = this->windows[ c ];
if( !w.isVisible())
continue; continue;
XFixesSetPictureClipRegion( display(), buffer, 0, 0, data.savedClipRegion()); if( !w.isOpaque())
Picture picture = data.picture(); {
XRenderComposite( display(), PictOpSrc, picture, None, buffer, 0, 0, 0, 0, XserverRegion saved_clip_region = XFixesCreateRegion( display(), NULL, 0 );
c->x() + int( data.matrix.xTranslate()), c->y() + int( data.matrix.yTranslate()), c->width(), c->height()); XFixesCopyRegion( display(), saved_clip_region, region );
phase2.prepend( Phase2Data( &w, saved_clip_region ));
continue;
}
w.paint( region, PAINT_OPAQUE );
// Subtract the clients shape from the damage region
XserverRegion shape = w.shape();
assert( shape != None );
XFixesSubtractRegion( display(), region, region, shape );
} }
// Now walk the list bottom to top, drawing translucent and complicated windows. // Fill any areas of the root window not covered by windows
paintBackground( region );
// Now walk the list bottom to top, drawing translucent windows.
// That we draw bottom to top is important now since we're drawing translucent objects // That we draw bottom to top is important now since we're drawing translucent objects
// and also are clipping only by opaque windows. // and also are clipping only by opaque windows.
for( int i = 0; foreach( Phase2Data d, phase2 )
i < windows.count();
++i )
{ {
Toplevel* c = windows[ i ]; Window& w = *d.window;
WindowData& data = window_data[ c ]; w.paint( d.region, PAINT_TRANSLUCENT );
if( data.phase != 2 ) XFixesDestroyRegion( display(), d.region );
continue;
XFixesSetPictureClipRegion( display(), buffer, 0, 0, data.savedClipRegion());
Picture picture = data.picture();
Picture alpha = data.alphaMask();
if( data.simpleTransformation())
{
XRenderComposite( display(), PictOpOver, picture, alpha, buffer, 0, 0, 0, 0,
c->x() + int( data.matrix.xTranslate()), c->y() + int( data.matrix.yTranslate()), c->width(), c->height());
}
else
{
// TODO Okay, I'm at loss here. Whoever wants advanced transformations can implement
// it themselves. If not, they actually don't want it that badly *shrug*.
// setPictureMatrix( picture, data.matrix );
XRenderComposite( display(), PictOpSrc, picture, alpha, buffer, 0, 0, 0, 0,
c->x(), c->y(), c->width(), c->height());
// setPictureMatrix( picture, Matrix());
}
} }
// cleanup // copy composed buffer to the root window (clipped by original damage area)
for( int i = 0;
i < windows.count();
++i )
{
Toplevel* c = windows[ i ];
WindowData& data = window_data[ c ];
data.cleanup();
}
// copy composed buffer to the root window
XFixesSetPictureClipRegion( display(), buffer, 0, 0, None ); XFixesSetPictureClipRegion( display(), buffer, 0, 0, None );
XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight()); XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
XFlush( display()); XFlush( display());
XFixesDestroyRegion( display(), damage ); XFixesDestroyRegion( display(), region );
} }
void SceneXrender::resetWindowData( Toplevel* c ) void SceneXrender::paintBackground( XserverRegion region )
{ {
if( !window_data.contains( c )) XFixesSetPictureClipRegion( display(), buffer, 0, 0, region );
window_data[ c ] = WindowData( c, XRenderFindVisualFormat( display(), c->visual())); XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff };
WindowData& data = window_data[ c ]; XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
data.matrix = Matrix();
data.effect.opacity = c->opacity();
} }
void SceneXrender::windowGeometryShapeChanged( Toplevel* c ) void SceneXrender::windowGeometryShapeChanged( Toplevel* c )
{ {
if( !window_data.contains( c )) if( !windows.contains( c )) // this is ok, shape is not valid by default
return; return;
window_data[ c ].geometryShapeChanged(); Window& w = windows[ c ];
w.discardPicture();
w.discardShape();
w.discardAlpha();
} }
void SceneXrender::windowOpacityChanged( Toplevel* c ) void SceneXrender::windowOpacityChanged( Toplevel* c )
{ {
if( !window_data.contains( c )) if( !windows.contains( c )) // this is ok, alpha is created on demand
return; return;
window_data[ c ].opacityChanged(); Window& w = windows[ c ];
w.discardAlpha();
} }
void SceneXrender::windowDeleted( Toplevel* c ) void SceneXrender::windowDeleted( Toplevel* c )
{ {
assert( window_data.contains( c )); assert( windows.contains( c ));
window_data[ c ].free(); windows[ c ].free();
window_data.remove( c ); windows.remove( c );
} }
void SceneXrender::windowAdded( Toplevel* c ) void SceneXrender::windowAdded( Toplevel* c )
{ {
assert( !window_data.contains( c )); assert( !windows.contains( c ));
resetWindowData( c ); windows[ c ] = Window( c );
} }
// TODO handle xrandr changes // TODO handle xrandr changes
@ -229,84 +212,35 @@ void SceneXrender::createBuffer()
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
} }
void SceneXrender::setPictureMatrix( Picture pic, const Matrix& ) SceneXrender::Window::Window( Toplevel* c )
{ : toplevel( c )
if( pic == None )
return;
#if 0
XTransform t;
// ignore z axis
t.matrix[ 0 ][ 0 ] = XDoubleToFixed( 1 / m.m[ 0 ][ 0 ] );
t.matrix[ 0 ][ 1 ] = XDoubleToFixed( m.m[ 0 ][ 1 ] );
t.matrix[ 0 ][ 2 ] = -XDoubleToFixed( m.m[ 0 ][ 3 ] ); // translation seems to be inverted
t.matrix[ 1 ][ 0 ] = XDoubleToFixed( m.m[ 1 ][ 0 ] );
t.matrix[ 1 ][ 1 ] = XDoubleToFixed( 1 / m.m[ 1 ][ 1 ] );
t.matrix[ 1 ][ 2 ] = -XDoubleToFixed( m.m[ 1 ][ 3 ] );
t.matrix[ 2 ][ 0 ] = XDoubleToFixed( m.m[ 3 ][ 0 ] );
t.matrix[ 2 ][ 1 ] = XDoubleToFixed( m.m[ 3 ][ 1 ] );
t.matrix[ 2 ][ 2 ] = XDoubleToFixed( m.m[ 3 ][ 3 ] );
// and scaling seems to be wrong too
// or maybe I just don't get it, but anyway, for now
if( m.m[ 3 ][ 3 ] != 1 )
{
t.matrix[ 0 ][ 0 ] = XDoubleToFixed( 1 / m.m[ 0 ][ 0 ] * m.m[ 3 ][ 3 ] );
t.matrix[ 1 ][ 1 ] = XDoubleToFixed( 1 / m.m[ 1 ][ 1 ] * m.m[ 3 ][ 3 ] );
t.matrix[ 2 ][ 2 ] = XDoubleToFixed( 1 );
}
XRenderSetPictureTransform( display(), pic, &t );
if( t.matrix[ 0 ][ 0 ] != XDoubleToFixed( 1 )
|| t.matrix[ 1 ][ 1 ] != XDoubleToFixed( 1 )
|| t.matrix[ 2 ][ 2 ] != XDoubleToFixed( 1 )
|| t.matrix[ 0 ][ 1 ] != XDoubleToFixed( 0 )
|| t.matrix[ 1 ][ 0 ] != XDoubleToFixed( 0 ))
{
XRenderSetPictureFilter( display(), pic, const_cast< char* >( FilterGood ), 0, 0 );
}
else // fast filter for identity or translation
{
XRenderSetPictureFilter( display(), pic, const_cast< char* >( FilterFast ), 0, 0 );
}
#endif
}
SceneXrender::WindowData::WindowData( Toplevel* c, XRenderPictFormat* f )
: window( c )
, _picture( None ) , _picture( None )
, format( f ) , format( XRenderFindVisualFormat( display(), c->visual()))
, saved_clip_region( None )
, alpha( None ) , alpha( None )
, _shape( None ) , _shape( None )
{ {
} }
void SceneXrender::WindowData::free() void SceneXrender::Window::free()
{ {
if( _picture != None ) discardPicture();
XRenderFreePicture( display(), _picture ); discardAlpha();
if( alpha != None ) discardShape();
XRenderFreePicture( display(), alpha );
if( _shape != None )
XRenderFreePicture( display(), _shape );
} }
bool SceneXrender::WindowData::simpleTransformation() const Picture SceneXrender::Window::picture()
{ {
return ( matrix.isIdentity() || matrix.isOnlyTranslate()); if( !toplevel->damage().isEmpty() && _picture != None )
}
Picture SceneXrender::WindowData::picture()
{
if( !window->damage().isEmpty() && _picture != None )
{ {
XRenderFreePicture( display(), _picture ); XRenderFreePicture( display(), _picture );
_picture = None; _picture = None;
} }
if( _picture == None && format != NULL ) if( _picture == None && format != NULL )
{ {
Pixmap window_pix = window->createWindowPixmap(); Pixmap window_pix = toplevel->createWindowPixmap();
Pixmap pix = window_pix; Pixmap pix = window_pix;
// HACK the same like with opengl // HACK the same like with opengl
Client* c = dynamic_cast< Client* >( window ); Client* c = dynamic_cast< Client* >( toplevel );
bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder(); bool alpha_clear = c != NULL && c->hasAlpha() && !c->noBorder();
#define ALPHA_CLEAR_COPY #define ALPHA_CLEAR_COPY
#ifdef ALPHA_CLEAR_COPY #ifdef ALPHA_CLEAR_COPY
@ -343,37 +277,33 @@ Picture SceneXrender::WindowData::picture()
return _picture; return _picture;
} }
void SceneXrender::WindowData::saveClipRegion( XserverRegion r )
void SceneXrender::Window::discardPicture()
{ {
saved_clip_region = XFixesCreateRegion( display(), NULL, 0 ); if( _picture != None )
XFixesCopyRegion( display(), saved_clip_region, r ); XRenderFreePicture( display(), _picture );
_picture = None;
} }
XserverRegion SceneXrender::WindowData::savedClipRegion() void SceneXrender::Window::discardAlpha()
{ {
return saved_clip_region; if( alpha != None )
XRenderFreePicture( display(), alpha );
alpha = None;
} }
void SceneXrender::WindowData::cleanup() void SceneXrender::Window::discardShape()
{ {
XFixesDestroyRegion( display(), saved_clip_region ); if( _shape != None )
saved_clip_region = None; XRenderFreePicture( display(), _shape );
_shape = None;
} }
bool SceneXrender::WindowData::isOpaque() const Picture SceneXrender::Window::alphaMask()
{
if( format->type == PictTypeDirect && format->direct.alphaMask )
return false;
if( effect.opacity != 1.0 )
return false;
return true;
}
Picture SceneXrender::WindowData::alphaMask()
{ {
if( isOpaque()) if( isOpaque())
return None; return None;
if( alpha != None && alpha_cached_opacity != effect.opacity ) if( alpha != None && alpha_cached_opacity != toplevel->opacity())
{ {
if( alpha != None ) if( alpha != None )
XRenderFreePicture( display(), alpha ); XRenderFreePicture( display(), alpha );
@ -381,7 +311,7 @@ Picture SceneXrender::WindowData::alphaMask()
} }
if( alpha != None ) if( alpha != None )
return alpha; return alpha;
if( effect.opacity == 1.0 ) if( toplevel->opacity() == 1.0 )
{ // no need to create alpha mask { // no need to create alpha mask
alpha_cached_opacity = 1.0; alpha_cached_opacity = 1.0;
return None; return None;
@ -393,54 +323,75 @@ Picture SceneXrender::WindowData::alphaMask()
alpha = XRenderCreatePicture( display(), pixmap, format, CPRepeat, &pa ); alpha = XRenderCreatePicture( display(), pixmap, format, CPRepeat, &pa );
XFreePixmap( display(), pixmap ); XFreePixmap( display(), pixmap );
XRenderColor col; XRenderColor col;
col.alpha = int( effect.opacity * 0xffff ); col.alpha = int( toplevel->opacity() * 0xffff );
alpha_cached_opacity = effect.opacity; alpha_cached_opacity = toplevel->opacity();
XRenderFillRectangle( display(), PictOpSrc, alpha, &col, 0, 0, 1, 1 ); XRenderFillRectangle( display(), PictOpSrc, alpha, &col, 0, 0, 1, 1 );
return alpha; return alpha;
} }
XserverRegion SceneXrender::Window::shape()
XserverRegion SceneXrender::WindowData::shape()
{ {
#if 0 // it probably doesn't make sense to cache this, and perhaps some others - they aren't roundtrips #if 0 // it probably doesn't make sense to cache this, and perhaps some others - they aren't roundtrips
if( shape == None ) if( shape == None )
{ {
shape = XFixesCreateRegionFromWindow( display(), window->handle(), WindowRegionBounding ); shape = XFixesCreateRegionFromWindow( display(), toplevel->handle(), WindowRegionBounding );
XFixesTranslateRegion( display(), shape, window->x(), window->y()); XFixesTranslateRegion( display(), shape, toplevel->x(), toplevel->y());
} }
return shape; return shape;
#else #else
if( !simpleTransformation()) XserverRegion shape = XFixesCreateRegionFromWindow( display(), toplevel->handle(), WindowRegionBounding );
{ XFixesTranslateRegion( display(), shape, toplevel->x(), toplevel->y());
// The region here should be translated using the matrix, but that's not possible
// (well, maybe fetch the region and transform manually - TODO check).
return None;
}
XserverRegion shape = XFixesCreateRegionFromWindow( display(), window->handle(), WindowRegionBounding );
XFixesTranslateRegion( display(), shape,
window->x() + int( matrix.xTranslate()), window->y() + int( matrix.yTranslate()));
return shape; return shape;
#endif #endif
} }
void SceneXrender::WindowData::geometryShapeChanged() void SceneXrender::Window::paint( XserverRegion region, int mask )
{ {
if( _picture != None ) if( mask & ( PAINT_OPAQUE | PAINT_TRANSLUCENT ))
XRenderFreePicture( display(), _picture ); {}
_picture = None; else if( mask & PAINT_OPAQUE )
if( alpha != None ) {
XRenderFreePicture( display(), alpha ); if( !isOpaque())
alpha = None; return;
if( _shape != None ) }
XFixesDestroyRegion( display(), _shape ); else if( mask & PAINT_TRANSLUCENT )
_shape = None; {
if( isOpaque())
return;
}
XFixesSetPictureClipRegion( display(), buffer, 0, 0, region );
Picture pic = picture();
if( pic == None ) // The render format can be null for GL and/or Xv visuals
return;
if( isOpaque())
{
XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0,
toplevel->x(), toplevel->y(), toplevel->width(), toplevel->height());
}
else
{
Picture alpha = alphaMask();
XRenderComposite( display(), PictOpOver, pic, alpha, buffer, 0, 0, 0, 0,
toplevel->x(), toplevel->y(), toplevel->width(), toplevel->height());
}
XFixesSetPictureClipRegion( display(), buffer, 0, 0, None );
} }
void SceneXrender::WindowData::opacityChanged() bool SceneXrender::Window::isVisible() const
{ {
if( alpha != None ) // TODO mapping state?
XRenderFreePicture( display(), alpha ); return !toplevel->geometry()
alpha = None; .intersect( QRect( 0, 0, displayWidth(), displayHeight()))
.isEmpty();
}
bool SceneXrender::Window::isOpaque() const
{
if( format->type == PictTypeDirect && format->direct.alphaMask )
return false;
if( toplevel->opacity() != 1.0 )
return false;
return true;
} }
} // namespace } // namespace

View file

@ -37,40 +37,52 @@ class SceneXrender
virtual void windowDeleted( Toplevel* ); virtual void windowDeleted( Toplevel* );
private: private:
void createBuffer(); void createBuffer();
void resetWindowData( Toplevel* c ); void paintGenericScreen( ToplevelList windows );
static void setPictureMatrix( Picture pic, const Matrix& m ); void paintSimpleScreen( QRegion damage, ToplevelList windows );
void paintBackground( XserverRegion region );
enum
{
PAINT_OPAQUE = 1 << 0,
PAINT_TRANSLUCENT = 1 << 1
};
XRenderPictFormat* format; XRenderPictFormat* format;
Picture front; Picture front;
Picture buffer; static Picture buffer;
class WindowData class Window;
static XserverRegion infiniteRegion;
QMap< Toplevel*, Window > windows;
struct Phase2Data
{ {
public: Phase2Data( Window* w, XserverRegion r ) : window( w ), region( r ) {}
WindowData( Toplevel* c, XRenderPictFormat* f ); Window* window;
void free(); // is often copied by value, use manually instead of dtor XserverRegion region;
void cleanup(); // removes data needed only during painting pass
Picture picture();
bool simpleTransformation() const;
void saveClipRegion( XserverRegion r );
XserverRegion savedClipRegion();
bool isOpaque() const;
Picture alphaMask();
XserverRegion shape();
void geometryShapeChanged();
void opacityChanged();
Matrix matrix;
EffectData effect;
int phase;
WindowData() {} // QMap sucks even in Qt4
private:
Toplevel* window;
Picture _picture;
XRenderPictFormat* format;
XserverRegion saved_clip_region;
Picture alpha;
double alpha_cached_opacity;
XserverRegion _shape;
}; };
QMap< Toplevel*, WindowData > window_data; };
class SceneXrender::Window
{
public:
Window( Toplevel* c );
void free(); // is often copied by value, use manually instead of dtor
void paint( XserverRegion region, int mask );
bool isOpaque() const;
void geometryShapeChanged();
void opacityChanged();
bool isVisible() const;
XserverRegion shape();
void discardPicture();
void discardShape();
void discardAlpha();
Window() {} // QMap sucks even in Qt4
private:
Picture picture();
Picture alphaMask();
Toplevel* toplevel;
Picture _picture;
XRenderPictFormat* format;
Picture alpha;
double alpha_cached_opacity;
XserverRegion _shape;
}; };
} // namespace } // namespace