GLX_EXT_texture_from_pixmap working.
svn path=/branches/work/kwin_composite/; revision=593460
This commit is contained in:
parent
71b0978628
commit
0858d34ed1
2 changed files with 130 additions and 45 deletions
163
scene_opengl.cpp
163
scene_opengl.cpp
|
@ -17,6 +17,8 @@ Based on glcompmgr code by Felix Bellaby.
|
|||
#include "utils.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
namespace KWinInternal
|
||||
|
@ -29,6 +31,13 @@ namespace KWinInternal
|
|||
GLXFBConfig SceneOpenGL::fbcdrawable;
|
||||
GLXContext SceneOpenGL::context;
|
||||
GLXPixmap SceneOpenGL::glxroot;
|
||||
bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap)
|
||||
|
||||
typedef void (*glXBindTexImageEXT_func)( Display* dpy, GLXDrawable drawable,
|
||||
int buffer, const int* attrib_list );
|
||||
typedef void (*glXReleaseTexImageEXT_func)( Display* dpy, GLXDrawable drawable, int buffer );
|
||||
glXBindTexImageEXT_func glXBindTexImageEXT;
|
||||
glXReleaseTexImageEXT_func glXReleaseTexImageEXT;
|
||||
|
||||
static void checkGLError( const char* txt )
|
||||
{
|
||||
|
@ -63,6 +72,20 @@ const int drawable_attrs[] =
|
|||
None
|
||||
};
|
||||
|
||||
const int drawable_tfp_attrs[] =
|
||||
{
|
||||
GLX_DOUBLEBUFFER, False,
|
||||
GLX_DEPTH_SIZE, 0,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_ALPHA_SIZE, 1,
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT,
|
||||
GLX_BIND_TO_TEXTURE_RGBA_EXT, True, // additional for tfp
|
||||
None
|
||||
};
|
||||
|
||||
SceneOpenGL::SceneOpenGL( Workspace* ws )
|
||||
: Scene( ws )
|
||||
{
|
||||
|
@ -70,13 +93,30 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
|
|||
int dummy;
|
||||
if( !glXQueryExtension( display(), &dummy, &dummy ))
|
||||
return;
|
||||
glXBindTexImageEXT = (glXBindTexImageEXT_func)
|
||||
dlsym( RTLD_DEFAULT, "glXBindTexImageEXT" );
|
||||
glXReleaseTexImageEXT = (glXReleaseTexImageEXT_func)
|
||||
dlsym( RTLD_DEFAULT, "glXReleaseTexImageEXT" );
|
||||
tfp_mode = ( glXBindTexImageEXT != NULL && glXReleaseTexImageEXT != NULL );
|
||||
XGCValues gcattr;
|
||||
gcattr.subwindow_mode = IncludeInferiors;
|
||||
gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr );
|
||||
buffer = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(),
|
||||
QX11Info::appDepth());
|
||||
findConfig( root_attrs, fbcroot );
|
||||
findConfig( drawable_attrs, fbcdrawable );
|
||||
if( !findConfig( root_attrs, fbcroot ))
|
||||
assert( false );
|
||||
if( tfp_mode )
|
||||
{
|
||||
if( !findConfig( drawable_tfp_attrs, fbcdrawable ))
|
||||
{
|
||||
tfp_mode = false;
|
||||
if( !findConfig( drawable_attrs, fbcdrawable ))
|
||||
assert( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
if( !findConfig( drawable_attrs, fbcdrawable ))
|
||||
assert( false );
|
||||
glxroot = glXCreatePixmap( display(), fbcroot, buffer, NULL );
|
||||
context = glXCreateNewContext( display(), fbcroot, GLX_RGBA_TYPE, NULL, GL_FALSE );
|
||||
glXMakeContextCurrent( display(), glxroot, glxroot, context );
|
||||
|
@ -131,22 +171,9 @@ bool SceneOpenGL::findConfig( const int* attrs, GLXFBConfig& config )
|
|||
pos += 2;
|
||||
}
|
||||
}
|
||||
assert( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
static void quadDraw( int x, int y, int w, int h )
|
||||
{
|
||||
glTexCoord2i( x, y );
|
||||
glVertex2i( x, y );
|
||||
glTexCoord2i( x + w, y );
|
||||
glVertex2i( x + w, y );
|
||||
glTexCoord2i( x + w, y + h );
|
||||
glVertex2i( x + w, y + h );
|
||||
glTexCoord2i( x, y + h );
|
||||
glVertex2i( x, y + h );
|
||||
}
|
||||
|
||||
void SceneOpenGL::paint( QRegion, ToplevelList windows )
|
||||
{
|
||||
grabXServer();
|
||||
|
@ -227,6 +254,9 @@ void SceneOpenGL::windowOpacityChanged( Toplevel* )
|
|||
SceneOpenGL::Window::Window( Toplevel* c )
|
||||
: toplevel( c )
|
||||
, texture( 0 )
|
||||
, texture_y_inverted( false )
|
||||
, bound_pixmap( None )
|
||||
, bound_glxpixmap( None )
|
||||
, shape_valid( false )
|
||||
, depth( 0 )
|
||||
{
|
||||
|
@ -249,12 +279,14 @@ void SceneOpenGL::Window::setDepth( int d )
|
|||
|
||||
void SceneOpenGL::Window::bindTexture()
|
||||
{
|
||||
if( texture != 0 && toplevel->damage().isEmpty())
|
||||
if( texture != 0 && toplevel->damage().isEmpty()
|
||||
&& !tfp_mode ) // interestingly this makes tfp slower
|
||||
{
|
||||
// texture doesn't need updating, just bind it
|
||||
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
|
||||
return;
|
||||
}
|
||||
// TODO cache pixmaps here if possible
|
||||
Pixmap window_pix = toplevel->createWindowPixmap();
|
||||
Pixmap pix = window_pix;
|
||||
// HACK
|
||||
|
@ -293,42 +325,86 @@ void SceneOpenGL::Window::bindTexture()
|
|||
XFillRectangle( display(), pix, gc, tw, 0, c->width() - tw, c->height());
|
||||
XFreeGC( display(), gc );
|
||||
}
|
||||
GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawable, pix, NULL );
|
||||
glXMakeContextCurrent( display(), pixmap, pixmap, context );
|
||||
glReadBuffer( GL_FRONT );
|
||||
glDrawBuffer( GL_FRONT );
|
||||
if( texture == None )
|
||||
if( tfp_mode )
|
||||
{
|
||||
glGenTextures( 1, &texture );
|
||||
if( texture == None )
|
||||
glGenTextures( 1, &texture );
|
||||
if( bound_pixmap != None )
|
||||
{
|
||||
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
|
||||
glXDestroyGLXPixmap( display(), bound_glxpixmap );
|
||||
XFreePixmap( display(), bound_pixmap );
|
||||
}
|
||||
static const int attrs[] =
|
||||
{
|
||||
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
|
||||
None
|
||||
};
|
||||
bound_pixmap = pix;
|
||||
bound_glxpixmap = glXCreatePixmap( display(), fbcdrawable, pix, attrs );
|
||||
int value;
|
||||
glXGetFBConfigAttrib( display(), fbcdrawable, GLX_Y_INVERTED_EXT, &value );
|
||||
texture_y_inverted = value ? true : false;
|
||||
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
|
||||
glCopyTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0,
|
||||
toplevel->hasAlpha() ? GL_RGBA : GL_RGB,
|
||||
0, 0, toplevel->width(), toplevel->height(), 0 );
|
||||
glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
|
||||
if( !toplevel->damage().isEmpty())
|
||||
GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawable, pix, NULL );
|
||||
glXMakeContextCurrent( display(), pixmap, pixmap, context );
|
||||
glReadBuffer( GL_FRONT );
|
||||
glDrawBuffer( GL_FRONT );
|
||||
if( texture == None )
|
||||
{
|
||||
foreach( QRect r, toplevel->damage().rects())
|
||||
glGenTextures( 1, &texture );
|
||||
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
|
||||
glCopyTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0,
|
||||
toplevel->hasAlpha() ? GL_RGBA : GL_RGB,
|
||||
0, 0, toplevel->width(), toplevel->height(), 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
|
||||
if( !toplevel->damage().isEmpty())
|
||||
{
|
||||
int gly = height() - r.y() - r.height(); // to opengl coords
|
||||
glCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0,
|
||||
r.x(), gly, r.x(), gly, r.width(), r.height());
|
||||
foreach( QRect r, toplevel->damage().rects())
|
||||
{
|
||||
int gly = height() - r.y() - r.height(); // to opengl coords
|
||||
glCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0,
|
||||
r.x(), gly, r.x(), gly, r.width(), r.height());
|
||||
}
|
||||
}
|
||||
}
|
||||
// the pixmap is no longer needed, the texture will be updated
|
||||
// only when the window changes anyway, so no need to cache
|
||||
// the pixmap
|
||||
glXDestroyPixmap( display(), pixmap );
|
||||
XFreePixmap( display(), pix );
|
||||
}
|
||||
// the pixmap is no longer needed, the texture will be updated
|
||||
// only when the window changes anyway, so no need to cache
|
||||
// the pixmap
|
||||
glXDestroyPixmap( display(), pixmap );
|
||||
XFreePixmap( display(), pix );
|
||||
#ifdef ALPHA_CLEAR_COPY
|
||||
if( alpha_clear )
|
||||
XFreePixmap( display(), window_pix );
|
||||
#endif
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::discardTexture()
|
||||
{
|
||||
if( texture != 0 )
|
||||
{
|
||||
if( tfp_mode )
|
||||
{
|
||||
glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
|
||||
glXDestroyGLXPixmap( display(), bound_glxpixmap );
|
||||
XFreePixmap( display(), bound_pixmap );
|
||||
bound_pixmap = None;
|
||||
bound_glxpixmap = None;
|
||||
}
|
||||
glDeleteTextures( 1, &texture );
|
||||
}
|
||||
texture = 0;
|
||||
}
|
||||
|
||||
|
||||
void SceneOpenGL::Window::discardShape()
|
||||
{
|
||||
shape_valid = false;
|
||||
|
@ -364,6 +440,18 @@ QRegion SceneOpenGL::Window::shape() const
|
|||
return shape_region;
|
||||
}
|
||||
|
||||
static void quadDraw( int x1, int y1, int x2, int y2, bool invert_y )
|
||||
{
|
||||
glTexCoord2i( x1, invert_y ? y2 : y1 );
|
||||
glVertex2i( x1, y1 );
|
||||
glTexCoord2i( x2, invert_y ? y2 : y1 );
|
||||
glVertex2i( x2, y1 );
|
||||
glTexCoord2i( x2, invert_y ? y1 : y2 );
|
||||
glVertex2i( x2, y2 );
|
||||
glTexCoord2i( x1, invert_y ? y1 : y2 );
|
||||
glVertex2i( x1, y2 );
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::draw()
|
||||
{
|
||||
// TODO for double-buffered root glDrawBuffer( GL_BACK );
|
||||
|
@ -380,7 +468,8 @@ void SceneOpenGL::Window::draw()
|
|||
glEnable( GL_TEXTURE_RECTANGLE_ARB );
|
||||
glBegin( GL_QUADS );
|
||||
foreach( QRect r, shape().rects())
|
||||
quadDraw( r.x(), height() - r.y() - r.height(), r.width(), r.height());
|
||||
quadDraw( r.x(), height() - r.y() - r.height(),
|
||||
r.x() + r.width(), height() - r.y(), texture_y_inverted );
|
||||
glEnd();
|
||||
glPopMatrix();
|
||||
if( toplevel->opacity() != 1.0 )
|
||||
|
|
|
@ -40,6 +40,7 @@ class SceneOpenGL
|
|||
static GLXFBConfig fbcdrawable;
|
||||
static GLXPixmap glxroot;
|
||||
static GLXContext context;
|
||||
static bool tfp_mode;
|
||||
class Window;
|
||||
QMap< Toplevel*, Window > windows;
|
||||
};
|
||||
|
@ -66,6 +67,9 @@ class SceneOpenGL::Window
|
|||
private:
|
||||
Toplevel* toplevel;
|
||||
Texture texture;
|
||||
bool texture_y_inverted;
|
||||
Pixmap bound_pixmap;
|
||||
GLXPixmap bound_glxpixmap; // only for tfp_mode
|
||||
mutable QRegion shape_region;
|
||||
mutable bool shape_valid;
|
||||
int depth;
|
||||
|
@ -95,14 +99,6 @@ int SceneOpenGL::Window::height() const
|
|||
return toplevel->height();
|
||||
}
|
||||
|
||||
inline
|
||||
void SceneOpenGL::Window::discardTexture()
|
||||
{
|
||||
if( texture != 0 )
|
||||
glDeleteTextures( 1, &texture );
|
||||
texture = 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue