2010-11-21 13:01:39 +00:00
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project .
Copyright ( C ) 2006 Lubos Lunak < l . lunak @ kde . org >
2012-08-26 15:14:23 +00:00
Copyright ( C ) 2012 Martin Gräßlin < mgraesslin @ kde . org >
2010-11-21 13:01:39 +00:00
Based on glcompmgr code by Felix Bellaby .
Using code from Compiz and Beryl .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-08-26 15:14:23 +00:00
// TODO: cmake magic
# ifndef KWIN_HAVE_OPENGLES
// own
# include "glxbackend.h"
// kwin
# include "options.h"
# include "utils.h"
# include "overlaywindow.h"
// kwin libs
# include <kwinglplatform.h>
// KDE
# include <KDE/KDebug>
# include <KDE/KXErrorHandler>
namespace KWin
{
GlxBackend : : GlxBackend ( )
: OpenGLBackend ( )
2013-01-26 15:05:51 +00:00
, gcroot ( None )
2013-03-11 15:05:47 +00:00
, drawable ( None )
, fbconfig_db ( NULL )
, fbconfig_nondb ( NULL )
, fbconfig ( NULL )
, glxDrawable ( None )
, ctx ( None )
2012-11-13 21:19:01 +00:00
, haveSwapInterval ( false )
2012-08-26 15:14:23 +00:00
{
init ( ) ;
}
GlxBackend : : ~ GlxBackend ( )
{
// TODO: cleanup in error case
// do cleanup after initBuffer()
cleanupGL ( ) ;
glXMakeCurrent ( display ( ) , None , NULL ) ;
2013-03-11 15:05:47 +00:00
if ( ctx )
glXDestroyContext ( display ( ) , ctx ) ;
2012-08-26 15:14:23 +00:00
if ( overlayWindow ( ) - > window ( ) ) {
2013-03-11 15:07:04 +00:00
if ( glxDrawable )
2013-03-11 15:05:47 +00:00
glXDestroyWindow ( display ( ) , glxDrawable ) ;
if ( drawable )
XDestroyWindow ( display ( ) , drawable ) ;
2012-08-26 15:14:23 +00:00
overlayWindow ( ) - > destroy ( ) ;
} else {
2013-03-11 15:05:47 +00:00
if ( glxDrawable )
glXDestroyPixmap ( display ( ) , glxDrawable ) ;
2013-01-26 15:05:51 +00:00
if ( gcroot )
XFreeGC ( display ( ) , gcroot ) ;
2013-03-11 15:05:47 +00:00
if ( drawable )
XFreePixmap ( display ( ) , drawable ) ;
2012-08-26 15:14:23 +00:00
}
checkGLError ( " Cleanup " ) ;
}
void GlxBackend : : init ( )
2011-01-30 14:34:42 +00:00
{
2010-11-21 13:01:39 +00:00
initGLX ( ) ;
2012-10-03 08:28:43 +00:00
// require at least GLX 1.3
if ( ! hasGLXVersion ( 1 , 3 ) ) {
setFailed ( " Requires at least GLX 1.3 " ) ;
return ;
2011-01-30 14:34:42 +00:00
}
2012-08-26 15:14:23 +00:00
if ( ! initDrawableConfigs ( ) ) {
setFailed ( " Could not initialize the drawable configs " ) ;
2010-11-21 13:01:39 +00:00
return ;
2011-01-30 14:34:42 +00:00
}
2012-08-26 15:14:23 +00:00
if ( ! initBuffer ( ) ) {
setFailed ( " Could not initialize the buffer " ) ;
return ;
2011-01-30 14:34:42 +00:00
}
2012-08-26 15:14:23 +00:00
if ( ! initRenderingContext ( ) ) {
setFailed ( " Could not initialize rendering context " ) ;
2011-04-28 20:06:21 +00:00
return ;
}
2012-08-26 15:14:23 +00:00
// Initialize OpenGL
GLPlatform * glPlatform = GLPlatform : : instance ( ) ;
2012-09-29 11:19:35 +00:00
glPlatform - > detect ( GlxPlatformInterface ) ;
2012-08-26 15:14:23 +00:00
glPlatform - > printResults ( ) ;
2012-09-29 11:19:35 +00:00
initGL ( GlxPlatformInterface ) ;
2010-11-21 13:01:39 +00:00
// Check whether certain features are supported
2012-11-13 21:19:01 +00:00
haveSwapInterval = glXSwapIntervalMESA | | glXSwapIntervalEXT | | glXSwapIntervalSGI ;
2012-03-29 20:11:28 +00:00
if ( options - > isGlVSync ( ) ) {
2013-03-11 15:05:47 +00:00
if ( glXGetVideoSync & & haveSwapInterval & & glXIsDirect ( display ( ) , ctx ) ) {
2012-03-29 20:11:28 +00:00
unsigned int sync ;
if ( glXGetVideoSync ( & sync ) = = 0 ) {
if ( glXWaitVideoSync ( 1 , 0 , & sync ) = = 0 ) {
// NOTICE at this time we should actually check whether we can successfully
// deactivate the swapInterval "glXSwapInterval(0) == 0"
// (because we don't actually want it active unless we explicitly run a glXSwapBuffers)
// However mesa/dri will return a range error (6) because deactivating the
// swapinterval (as of today) seems completely unsupported
2012-08-26 15:14:23 +00:00
setHasWaitSync ( true ) ;
2013-02-18 22:17:46 +00:00
setSwapInterval ( 1 ) ;
2012-03-29 20:11:28 +00:00
}
else
qWarning ( ) < < " NO VSYNC! glXWaitVideoSync(1,0,&uint) isn't 0 but " < < glXWaitVideoSync ( 1 , 0 , & sync ) ;
} else
qWarning ( ) < < " NO VSYNC! glXGetVideoSync(&uint) isn't 0 but " < < glXGetVideoSync ( & sync ) ;
2011-01-30 14:34:42 +00:00
} else
2012-11-13 21:19:01 +00:00
qWarning ( ) < < " NO VSYNC! glXGetVideoSync, haveSwapInterval, glXIsDirect " < <
2013-03-11 15:05:47 +00:00
bool ( glXGetVideoSync ) < < haveSwapInterval < < glXIsDirect ( display ( ) , ctx ) ;
2011-01-30 14:34:42 +00:00
}
2012-10-13 08:33:38 +00:00
if ( glPlatform - > isVirtualBox ( ) ) {
// VirtualBox does not support glxQueryDrawable
// this should actually be in kwinglutils_funcs, but QueryDrawable seems not to be provided by an extension
// and the GLPlatform has not been initialized at the moment when initGLX() is called.
glXQueryDrawable = NULL ;
}
2013-03-11 15:05:47 +00:00
setIsDirectRendering ( bool ( glXIsDirect ( display ( ) , ctx ) ) ) ;
2012-08-26 15:14:23 +00:00
kDebug ( 1212 ) < < " DB: " < < isDoubleBuffer ( ) < < " , Direct: " < < isDirectRendering ( ) < < endl ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
bool GlxBackend : : initRenderingContext ( )
2011-01-30 14:34:42 +00:00
{
2013-03-11 15:19:45 +00:00
bool direct = options - > isGlDirect ( ) ;
ctx = glXCreateNewContext ( display ( ) , fbconfig , GLX_RGBA_TYPE , NULL , direct ) ;
if ( ! ctx ) {
kDebug ( 1212 ) < < " Failed to create an OpenGL context. " ;
return false ;
}
if ( ! glXMakeCurrent ( display ( ) , glxDrawable , ctx ) ) {
kDebug ( 1212 ) < < " Failed to make the OpenGL context current. " ;
glXDestroyContext ( display ( ) , ctx ) ;
ctx = 0 ;
return false ;
2010-11-21 13:01:39 +00:00
}
2013-03-11 15:19:45 +00:00
2011-01-30 14:34:42 +00:00
return true ;
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
bool GlxBackend : : initBuffer ( )
2011-01-30 14:34:42 +00:00
{
2013-03-11 15:16:05 +00:00
if ( ! initFbConfig ( ) )
2010-11-21 13:01:39 +00:00
return false ;
2013-03-11 15:16:05 +00:00
2013-03-11 15:05:47 +00:00
if ( fbconfig_db ! = NULL & & overlayWindow ( ) - > create ( ) ) {
2011-01-30 14:34:42 +00:00
// we have overlay, try to create double-buffered window in it
2013-03-11 15:05:47 +00:00
fbconfig = fbconfig_db ;
XVisualInfo * visual = glXGetVisualFromFBConfig ( display ( ) , fbconfig ) ;
2010-11-21 13:01:39 +00:00
XSetWindowAttributes attrs ;
2011-01-30 14:34:42 +00:00
attrs . colormap = XCreateColormap ( display ( ) , rootWindow ( ) , visual - > visual , AllocNone ) ;
2013-03-11 15:05:47 +00:00
drawable = XCreateWindow ( display ( ) , overlayWindow ( ) - > window ( ) , 0 , 0 , displayWidth ( ) , displayHeight ( ) ,
0 , visual - > depth , InputOutput , visual - > visual , CWColormap , & attrs ) ;
2013-03-11 15:07:04 +00:00
glxDrawable = glXCreateWindow ( display ( ) , fbconfig , drawable , NULL ) ;
2013-03-11 15:05:47 +00:00
overlayWindow ( ) - > setup ( drawable ) ;
2012-08-26 15:14:23 +00:00
setDoubleBuffer ( true ) ;
2011-01-30 14:34:42 +00:00
XFree ( visual ) ;
2013-03-11 15:05:47 +00:00
} else if ( fbconfig_nondb ! = NULL ) {
2011-01-30 14:34:42 +00:00
// cannot get any double-buffered drawable, will double-buffer using a pixmap
2013-03-11 15:05:47 +00:00
fbconfig = fbconfig_nondb ;
XVisualInfo * visual = glXGetVisualFromFBConfig ( display ( ) , fbconfig ) ;
2010-11-21 13:01:39 +00:00
XGCValues gcattr ;
gcattr . subwindow_mode = IncludeInferiors ;
2011-01-30 14:34:42 +00:00
gcroot = XCreateGC ( display ( ) , rootWindow ( ) , GCSubwindowMode , & gcattr ) ;
2013-03-11 15:05:47 +00:00
drawable = XCreatePixmap ( display ( ) , rootWindow ( ) , displayWidth ( ) , displayHeight ( ) ,
visual - > depth ) ;
glxDrawable = glXCreatePixmap ( display ( ) , fbconfig , drawable , NULL ) ;
2012-08-26 15:14:23 +00:00
setDoubleBuffer ( false ) ;
2011-01-30 14:34:42 +00:00
XFree ( visual ) ;
} else {
kError ( 1212 ) < < " Couldn't create output buffer (failed to create overlay window?) ! " ;
2010-11-21 13:01:39 +00:00
return false ; // error
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
int vis_buffer ;
2013-03-11 15:05:47 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfig , GLX_VISUAL_ID , & vis_buffer ) ;
XVisualInfo * visinfo_buffer = glXGetVisualFromFBConfig ( display ( ) , fbconfig ) ;
2011-01-30 14:34:42 +00:00
kDebug ( 1212 ) < < " Buffer visual (depth " < < visinfo_buffer - > depth < < " ): 0x " < < QString : : number ( vis_buffer , 16 ) ;
XFree ( visinfo_buffer ) ;
2010-11-21 13:01:39 +00:00
return true ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2013-03-11 15:16:05 +00:00
bool GlxBackend : : initFbConfig ( )
2011-01-30 14:34:42 +00:00
{
2013-03-11 15:16:05 +00:00
int attribs [ ] = {
GLX_RENDER_TYPE , GLX_RGBA_TYPE ,
GLX_RED_SIZE , 1 ,
GLX_GREEN_SIZE , 1 ,
GLX_BLUE_SIZE , 1 ,
GLX_ALPHA_SIZE , 0 ,
GLX_DEPTH_SIZE , 0 ,
GLX_STENCIL_SIZE , 0 ,
GLX_CONFIG_CAVEAT , GLX_NONE ,
GLX_DOUBLEBUFFER , true ,
0
} ;
2013-03-11 15:05:47 +00:00
fbconfig_db = NULL ;
fbconfig_nondb = NULL ;
2010-11-21 13:01:39 +00:00
2013-03-11 15:16:05 +00:00
// Try to find a double buffered configuration
int count = 0 ;
GLXFBConfig * configs = glXChooseFBConfig ( display ( ) , DefaultScreen ( display ( ) ) , attribs , & count ) ;
2012-10-30 17:20:00 +00:00
2013-03-11 15:16:05 +00:00
if ( count > 0 ) {
fbconfig_db = configs [ 0 ] ;
XFree ( configs ) ;
}
2012-10-30 17:20:00 +00:00
2013-03-11 15:16:05 +00:00
// Try to find a single buffered configuration
attribs [ 18 ] = false ;
configs = glXChooseFBConfig ( display ( ) , DefaultScreen ( display ( ) ) , attribs , & count ) ;
2012-10-30 17:20:00 +00:00
2013-03-11 15:16:05 +00:00
if ( count > 0 ) {
fbconfig_nondb = configs [ 0 ] ;
XFree ( configs ) ;
2011-01-30 14:34:42 +00:00
}
2013-03-11 15:16:05 +00:00
2013-03-11 15:05:47 +00:00
if ( fbconfig_db = = NULL & & fbconfig_nondb = = NULL ) {
2013-03-11 15:16:05 +00:00
kError ( 1212 ) < < " Failed to find a usable framebuffer configuration " ;
2010-11-21 13:01:39 +00:00
return false ;
2011-01-30 14:34:42 +00:00
}
2013-03-11 15:16:05 +00:00
2011-01-30 14:34:42 +00:00
return true ;
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
bool GlxBackend : : initDrawableConfigs ( )
2011-01-30 14:34:42 +00:00
{
2010-11-21 13:01:39 +00:00
int cnt ;
2011-01-30 14:34:42 +00:00
GLXFBConfig * fbconfigs = glXGetFBConfigs ( display ( ) , DefaultScreen ( display ( ) ) , & cnt ) ;
2010-11-21 13:01:39 +00:00
2011-01-30 14:34:42 +00:00
for ( int i = 0 ; i < = 32 ; i + + ) {
2010-11-21 13:01:39 +00:00
int back , stencil , depth , caveat , alpha , mipmap , rgba ;
back = INT_MAX ;
stencil = INT_MAX ;
depth = INT_MAX ;
caveat = INT_MAX ;
mipmap = 0 ;
rgba = 0 ;
fbcdrawableinfo [ i ] . fbconfig = NULL ;
fbcdrawableinfo [ i ] . bind_texture_format = 0 ;
fbcdrawableinfo [ i ] . texture_targets = 0 ;
fbcdrawableinfo [ i ] . y_inverted = 0 ;
fbcdrawableinfo [ i ] . mipmap = 0 ;
2011-01-30 14:34:42 +00:00
for ( int j = 0 ; j < cnt ; j + + ) {
2010-11-21 13:01:39 +00:00
XVisualInfo * vi ;
int visual_depth ;
2011-01-30 14:34:42 +00:00
vi = glXGetVisualFromFBConfig ( display ( ) , fbconfigs [ j ] ) ;
if ( vi = = NULL )
2010-11-21 13:01:39 +00:00
continue ;
visual_depth = vi - > depth ;
2011-01-30 14:34:42 +00:00
XFree ( vi ) ;
if ( visual_depth ! = i )
2010-11-21 13:01:39 +00:00
continue ;
int value ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_ALPHA_SIZE , & alpha ) ;
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_BUFFER_SIZE , & value ) ;
if ( value ! = i & & ( value - alpha ) ! = i )
2010-11-21 13:01:39 +00:00
continue ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_RENDER_TYPE , & value ) ;
if ( ! ( value & GLX_RGBA_BIT ) )
2010-11-21 13:01:39 +00:00
continue ;
2011-01-30 10:55:27 +00:00
value = 0 ;
2011-01-30 14:34:42 +00:00
if ( i = = 32 ) {
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_BIND_TO_TEXTURE_RGBA_EXT , & value ) ;
if ( value ) {
2011-01-30 10:55:27 +00:00
// TODO I think this should be set only after the config passes all tests
rgba = 1 ;
fbcdrawableinfo [ i ] . bind_texture_format = GLX_TEXTURE_FORMAT_RGBA_EXT ;
}
2011-01-30 14:34:42 +00:00
}
if ( ! value ) {
if ( rgba )
2011-01-30 10:55:27 +00:00
continue ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_BIND_TO_TEXTURE_RGB_EXT , & value ) ;
if ( ! value )
2011-01-30 10:55:27 +00:00
continue ;
fbcdrawableinfo [ i ] . bind_texture_format = GLX_TEXTURE_FORMAT_RGB_EXT ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
int back_value ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_DOUBLEBUFFER , & back_value ) ;
if ( back_value > back )
2010-11-21 13:01:39 +00:00
continue ;
int stencil_value ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_STENCIL_SIZE , & stencil_value ) ;
if ( stencil_value > stencil )
2010-11-21 13:01:39 +00:00
continue ;
int depth_value ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_DEPTH_SIZE , & depth_value ) ;
if ( depth_value > depth )
2010-11-21 13:01:39 +00:00
continue ;
int caveat_value ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_CONFIG_CAVEAT , & caveat_value ) ;
if ( caveat_value > caveat )
2010-11-21 13:01:39 +00:00
continue ;
// ok, config passed all tests, it's the best one so far
fbcdrawableinfo [ i ] . fbconfig = fbconfigs [ j ] ;
caveat = caveat_value ;
back = back_value ;
stencil = stencil_value ;
depth = depth_value ;
2012-06-13 23:23:48 +00:00
mipmap = 0 ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_BIND_TO_TEXTURE_TARGETS_EXT , & value ) ;
2011-01-30 10:55:27 +00:00
fbcdrawableinfo [ i ] . texture_targets = value ;
2011-01-30 14:34:42 +00:00
glXGetFBConfigAttrib ( display ( ) , fbconfigs [ j ] ,
GLX_Y_INVERTED_EXT , & value ) ;
2010-11-21 13:01:39 +00:00
fbcdrawableinfo [ i ] . y_inverted = value ;
fbcdrawableinfo [ i ] . mipmap = mipmap ;
}
2011-01-30 14:34:42 +00:00
}
if ( cnt )
XFree ( fbconfigs ) ;
if ( fbcdrawableinfo [ DefaultDepth ( display ( ) , DefaultScreen ( display ( ) ) ) ] . fbconfig = = NULL ) {
kError ( 1212 ) < < " Couldn't find framebuffer configuration for default depth! " ;
2010-11-21 13:01:39 +00:00
return false ;
2011-01-30 14:34:42 +00:00
}
if ( fbcdrawableinfo [ 32 ] . fbconfig = = NULL ) {
kError ( 1212 ) < < " Couldn't find framebuffer configuration for depth 32 (no ARGB GLX visual)! " ;
2010-11-21 13:01:39 +00:00
return false ;
}
2013-03-11 15:10:14 +00:00
for ( int i = 0 ; i < = 32 ; i + + ) {
if ( fbcdrawableinfo [ i ] . fbconfig = = NULL )
continue ;
int vis_drawable = 0 ;
glXGetFBConfigAttrib ( display ( ) , fbcdrawableinfo [ i ] . fbconfig , GLX_VISUAL_ID , & vis_drawable ) ;
kDebug ( 1212 ) < < " Drawable visual (depth " < < i < < " ): 0x " < < QString : : number ( vis_drawable , 16 ) ;
}
2011-01-30 14:34:42 +00:00
return true ;
}
2010-11-21 13:01:39 +00:00
2012-11-13 21:19:01 +00:00
void GlxBackend : : setSwapInterval ( int interval )
{
if ( glXSwapIntervalEXT )
2013-03-11 15:05:47 +00:00
glXSwapIntervalEXT ( display ( ) , glxDrawable , interval ) ;
2012-11-13 21:19:01 +00:00
else if ( glXSwapIntervalMESA )
glXSwapIntervalMESA ( interval ) ;
else if ( glXSwapIntervalSGI )
glXSwapIntervalSGI ( interval ) ;
}
2012-03-29 20:11:28 +00:00
# define VSYNC_DEBUG 0
2012-08-26 15:14:23 +00:00
void GlxBackend : : waitSync ( )
2011-01-30 14:34:42 +00:00
{
// NOTE that vsync has no effect with indirect rendering
if ( waitSyncAvailable ( ) ) {
2012-03-29 20:11:28 +00:00
# if VSYNC_DEBUG
2012-08-26 15:14:23 +00:00
startRenderTimer ( ) ;
2012-03-29 20:11:28 +00:00
# endif
2010-11-21 13:01:39 +00:00
uint sync ;
2012-03-29 20:11:28 +00:00
#if 0
// TODO: why precisely is this important?
// the sync counter /can/ perform multiple steps during glXGetVideoSync & glXWaitVideoSync
// but this only leads to waiting for two frames??!?
2011-01-30 14:34:42 +00:00
glXGetVideoSync ( & sync ) ;
glXWaitVideoSync ( 2 , ( sync + 1 ) % 2 , & sync ) ;
2012-07-17 23:50:43 +00:00
# else
2012-03-29 20:11:28 +00:00
glXWaitVideoSync ( 1 , 0 , & sync ) ;
2012-07-17 23:50:43 +00:00
# endif
2012-03-29 20:11:28 +00:00
# if VSYNC_DEBUG
2012-07-17 23:50:43 +00:00
static int waitTime = 0 , waitCounter = 0 , doubleSyncCounter = 0 ;
2012-08-26 15:14:23 +00:00
if ( renderTime ( ) > 11 )
2012-07-17 23:50:43 +00:00
+ + doubleSyncCounter ;
2012-08-26 15:14:23 +00:00
waitTime + = renderTime ( ) ;
2012-03-29 20:11:28 +00:00
+ + waitCounter ;
if ( waitCounter > 99 )
{
2012-07-17 23:50:43 +00:00
qDebug ( ) < < " mean vsync wait time: " < < float ( ( float ) waitTime / ( float ) waitCounter ) < < doubleSyncCounter < < " /100 " ;
doubleSyncCounter = waitTime = waitCounter = 0 ;
2012-03-29 20:11:28 +00:00
}
# endif
2010-11-21 13:01:39 +00:00
}
2012-08-26 15:14:23 +00:00
startRenderTimer ( ) ; // yes, the framerate shall be constant anyway.
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-03-29 20:11:28 +00:00
# undef VSYNC_DEBUG
2012-10-07 11:43:31 +00:00
void GlxBackend : : present ( )
2011-01-30 14:34:42 +00:00
{
2012-08-26 15:14:23 +00:00
if ( isDoubleBuffer ( ) ) {
2013-03-10 21:18:30 +00:00
const QRegion displayRegion ( 0 , 0 , displayWidth ( ) , displayHeight ( ) ) ;
const bool fullRepaint = ( lastDamage ( ) = = displayRegion ) ;
2013-02-18 22:17:46 +00:00
if ( fullRepaint ) {
2012-11-13 21:19:01 +00:00
if ( haveSwapInterval ) {
2013-03-11 15:05:47 +00:00
glXSwapBuffers ( display ( ) , glxDrawable ) ;
2013-02-18 22:17:46 +00:00
startRenderTimer ( ) ;
2012-03-29 20:11:28 +00:00
} else {
2013-02-18 22:17:46 +00:00
waitSync ( ) ; // calls startRenderTimer();
2013-03-11 15:05:47 +00:00
glXSwapBuffers ( display ( ) , glxDrawable ) ;
2012-03-29 20:11:28 +00:00
}
2013-02-18 22:17:46 +00:00
} else if ( glXCopySubBuffer ) {
waitSync ( ) ;
foreach ( const QRect & r , lastDamage ( ) . rects ( ) ) {
// convert to OpenGL coordinates
int y = displayHeight ( ) - r . y ( ) - r . height ( ) ;
2013-03-11 15:05:47 +00:00
glXCopySubBuffer ( display ( ) , glxDrawable , r . x ( ) , y , r . width ( ) , r . height ( ) ) ;
2013-02-18 22:17:46 +00:00
}
} else { // Copy Pixels
// if a shader is bound or the texture unit is enabled, copy pixels results in a black screen
// therefore unbind the shader and restore after copying the pixels
GLint shader = 0 ;
if ( ShaderManager : : instance ( ) - > isShaderBound ( ) ) {
glGetIntegerv ( GL_CURRENT_PROGRAM , & shader ) ;
glUseProgram ( 0 ) ;
}
bool reenableTexUnit = false ;
if ( glIsEnabled ( GL_TEXTURE_2D ) ) {
glDisable ( GL_TEXTURE_2D ) ;
reenableTexUnit = true ;
}
// no idea why glScissor() is used, but Compiz has it and it doesn't seem to hurt
glEnable ( GL_SCISSOR_TEST ) ;
glDrawBuffer ( GL_FRONT ) ;
waitSync ( ) ;
int xpos = 0 ;
int ypos = 0 ;
foreach ( const QRect & r , lastDamage ( ) . rects ( ) ) {
// convert to OpenGL coordinates
int y = displayHeight ( ) - r . y ( ) - r . height ( ) ;
// Move raster position relatively using glBitmap() rather
// than using glRasterPos2f() - the latter causes drawing
// artefacts at the bottom screen edge with some gfx cards
// glRasterPos2f( r.x(), r.y() + r.height());
glBitmap ( 0 , 0 , 0 , 0 , r . x ( ) - xpos , y - ypos , NULL ) ;
xpos = r . x ( ) ;
ypos = y ;
glScissor ( r . x ( ) , y , r . width ( ) , r . height ( ) ) ;
glCopyPixels ( r . x ( ) , y , r . width ( ) , r . height ( ) , GL_COLOR ) ;
}
glBitmap ( 0 , 0 , 0 , 0 , - xpos , - ypos , NULL ) ; // move position back to 0,0
glDrawBuffer ( GL_BACK ) ;
glDisable ( GL_SCISSOR_TEST ) ;
if ( reenableTexUnit ) {
glEnable ( GL_TEXTURE_2D ) ;
}
// rebind previously bound shader
if ( ShaderManager : : instance ( ) - > isShaderBound ( ) ) {
glUseProgram ( shader ) ;
}
2010-11-21 13:01:39 +00:00
}
2013-02-18 22:17:46 +00:00
2011-01-30 14:34:42 +00:00
glXWaitGL ( ) ;
} else {
2010-11-21 13:01:39 +00:00
glXWaitGL ( ) ;
2013-03-10 21:18:30 +00:00
foreach ( const QRect & r , lastDamage ( ) . rects ( ) )
2013-03-11 15:05:47 +00:00
XCopyArea ( display ( ) , drawable , rootWindow ( ) , gcroot , r . x ( ) , r . y ( ) , r . width ( ) , r . height ( ) , r . x ( ) , r . y ( ) ) ;
2010-11-21 13:01:39 +00:00
}
2013-02-18 22:17:46 +00:00
setLastDamage ( QRegion ( ) ) ;
2012-03-29 20:11:28 +00:00
XFlush ( display ( ) ) ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
void GlxBackend : : screenGeometryChanged ( const QSize & size )
2011-11-26 15:15:46 +00:00
{
2012-08-26 15:14:23 +00:00
if ( overlayWindow ( ) - > window ( ) = = None ) {
2011-11-26 15:15:46 +00:00
glXMakeCurrent ( display ( ) , None , NULL ) ;
2013-03-11 15:05:47 +00:00
glXDestroyPixmap ( display ( ) , glxDrawable ) ;
XFreePixmap ( display ( ) , drawable ) ;
XVisualInfo * visual = glXGetVisualFromFBConfig ( display ( ) , fbconfig ) ;
drawable = XCreatePixmap ( display ( ) , rootWindow ( ) , size . width ( ) , size . height ( ) , visual - > depth ) ;
2011-11-26 15:15:46 +00:00
XFree ( visual ) ;
2013-03-11 15:05:47 +00:00
glxDrawable = glXCreatePixmap ( display ( ) , fbconfig , drawable , NULL ) ;
glXMakeCurrent ( display ( ) , glxDrawable , ctx ) ;
2011-11-26 15:15:46 +00:00
// TODO: there seems some bug, some clients become black until an eg. un/remap - could be a general pixmap buffer issue, though
2012-08-26 15:14:23 +00:00
} else {
2011-11-26 15:15:46 +00:00
glXMakeCurrent ( display ( ) , None , NULL ) ; // deactivate context ////
2013-03-11 15:05:47 +00:00
XMoveResizeWindow ( display ( ) , drawable , 0 , 0 , size . width ( ) , size . height ( ) ) ;
overlayWindow ( ) - > setup ( drawable ) ;
2011-11-26 15:15:46 +00:00
XSync ( display ( ) , false ) ; // ensure X11 stuff has applied ////
2013-03-11 15:05:47 +00:00
glXMakeCurrent ( display ( ) , glxDrawable , ctx ) ; // reactivate context ////
2012-08-16 06:03:07 +00:00
glViewport ( 0 , 0 , size . width ( ) , size . height ( ) ) ; // adjust viewport last - should btw. be superfluous on the Pixmap buffer - iirc glXCreatePixmap sets the context anyway. ////
2011-11-26 15:15:46 +00:00
}
}
2012-08-26 15:14:23 +00:00
SceneOpenGL : : TexturePrivate * GlxBackend : : createBackendTexture ( SceneOpenGL : : Texture * texture )
{
return new GlxTexture ( texture , this ) ;
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
void GlxBackend : : prepareRenderingFrame ( )
2011-01-30 14:34:42 +00:00
{
2012-08-26 15:14:23 +00:00
if ( ! lastDamage ( ) . isEmpty ( ) )
2012-10-07 11:43:31 +00:00
present ( ) ;
2012-08-26 15:14:23 +00:00
glXWaitX ( ) ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2013-03-10 21:18:30 +00:00
void GlxBackend : : endRenderingFrame ( const QRegion & damage )
2012-08-26 15:14:23 +00:00
{
setLastDamage ( damage ) ;
glFlush ( ) ;
if ( overlayWindow ( ) - > window ( ) ) // show the window only after the first pass,
overlayWindow ( ) - > show ( ) ; // since that pass may take long
}
/********************************************************
* GlxTexture
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
GlxTexture : : GlxTexture ( SceneOpenGL : : Texture * texture , GlxBackend * backend )
: SceneOpenGL : : TexturePrivate ( )
, q ( texture )
, m_backend ( backend )
, m_glxpixmap ( None )
{
}
GlxTexture : : ~ GlxTexture ( )
2011-07-18 15:55:39 +00:00
{
if ( m_glxpixmap ! = None ) {
2012-02-20 09:25:13 +00:00
if ( ! options - > isGlStrictBinding ( ) ) {
2011-07-18 15:55:39 +00:00
glXReleaseTexImageEXT ( display ( ) , m_glxpixmap , GLX_FRONT_LEFT_EXT ) ;
2011-02-05 10:55:10 +00:00
}
2011-07-18 15:55:39 +00:00
glXDestroyPixmap ( display ( ) , m_glxpixmap ) ;
2011-08-25 08:29:23 +00:00
m_glxpixmap = None ;
2010-11-21 13:01:39 +00:00
}
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
void GlxTexture : : onDamage ( )
{
if ( options - > isGlStrictBinding ( ) & & m_glxpixmap ) {
glXReleaseTexImageEXT ( display ( ) , m_glxpixmap , GLX_FRONT_LEFT_EXT ) ;
glXBindTexImageEXT ( display ( ) , m_glxpixmap , GLX_FRONT_LEFT_EXT , NULL ) ;
}
GLTexturePrivate : : onDamage ( ) ;
}
void GlxTexture : : findTarget ( )
2011-01-30 14:34:42 +00:00
{
2010-11-21 13:01:39 +00:00
unsigned int new_target = 0 ;
2012-08-26 15:14:23 +00:00
if ( glXQueryDrawable & & m_glxpixmap ! = None )
glXQueryDrawable ( display ( ) , m_glxpixmap , GLX_TEXTURE_TARGET_EXT , & new_target ) ;
2011-02-05 10:56:48 +00:00
// HACK: this used to be a hack for Xgl.
// without this hack the NVIDIA blob aborts when trying to bind a texture from
// a pixmap icon
if ( new_target = = 0 ) {
2012-08-26 15:14:23 +00:00
if ( GLTexture : : NPOTTextureSupported ( ) | |
( isPowerOfTwo ( m_size . width ( ) ) & & isPowerOfTwo ( m_size . height ( ) ) ) ) {
2011-02-05 10:56:48 +00:00
new_target = GLX_TEXTURE_2D_EXT ;
} else {
new_target = GLX_TEXTURE_RECTANGLE_EXT ;
}
}
2011-01-30 14:34:42 +00:00
switch ( new_target ) {
case GLX_TEXTURE_2D_EXT :
2012-08-26 15:14:23 +00:00
m_target = GL_TEXTURE_2D ;
m_scale . setWidth ( 1.0f / m_size . width ( ) ) ;
m_scale . setHeight ( 1.0f / m_size . height ( ) ) ;
2011-01-30 14:34:42 +00:00
break ;
case GLX_TEXTURE_RECTANGLE_EXT :
2012-08-26 15:14:23 +00:00
m_target = GL_TEXTURE_RECTANGLE_ARB ;
m_scale . setWidth ( 1.0f ) ;
m_scale . setHeight ( 1.0f ) ;
2011-01-30 14:34:42 +00:00
break ;
default :
abort ( ) ;
2010-11-21 13:01:39 +00:00
}
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
bool GlxTexture : : loadTexture ( const Pixmap & pix , const QSize & size , int depth )
2011-01-30 14:34:42 +00:00
{
2010-11-21 13:01:39 +00:00
# ifdef CHECK_GL_ERROR
2011-01-30 14:34:42 +00:00
checkGLError ( " TextureLoad1 " ) ;
2010-11-21 13:01:39 +00:00
# endif
2011-01-30 14:34:42 +00:00
if ( pix = = None | | size . isEmpty ( ) | | depth < 1 )
2010-11-21 13:01:39 +00:00
return false ;
2012-08-26 15:14:23 +00:00
if ( m_backend - > fbcdrawableinfo [ depth ] . fbconfig = = NULL ) {
2011-01-30 14:34:42 +00:00
kDebug ( 1212 ) < < " No framebuffer configuration for depth " < < depth
< < " ; not binding pixmap " < < endl ;
2011-01-30 10:55:27 +00:00
return false ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
m_size = size ;
2011-07-18 15:55:39 +00:00
// new texture, or texture contents changed; mipmaps now invalid
2012-08-26 15:14:23 +00:00
q - > setDirty ( ) ;
2010-11-21 13:01:39 +00:00
# ifdef CHECK_GL_ERROR
2011-01-30 14:34:42 +00:00
checkGLError ( " TextureLoad2 " ) ;
2010-11-21 13:01:39 +00:00
# endif
2011-01-30 10:55:27 +00:00
// tfp mode, simply bind the pixmap to texture
2012-08-26 15:14:23 +00:00
glGenTextures ( 1 , & m_texture ) ;
2011-01-30 10:55:27 +00:00
// The GLX pixmap references the contents of the original pixmap, so it doesn't
// need to be recreated when the contents change.
// The texture may or may not use the same storage depending on the EXT_tfp
// implementation. When options->glStrictBinding is true, the texture uses
// a different storage and needs to be updated with a call to
// glXBindTexImageEXT() when the contents of the pixmap has changed.
2011-07-18 15:55:39 +00:00
int attrs [ ] = {
2012-08-26 15:14:23 +00:00
GLX_TEXTURE_FORMAT_EXT , m_backend - > fbcdrawableinfo [ depth ] . bind_texture_format ,
GLX_MIPMAP_TEXTURE_EXT , m_backend - > fbcdrawableinfo [ depth ] . mipmap > 0 ,
2011-07-18 15:55:39 +00:00
None , None , None
} ;
// Specifying the texture target explicitly is reported to cause a performance
// regression with R300G (see bug #256654).
if ( GLPlatform : : instance ( ) - > driver ( ) ! = Driver_R300G ) {
2012-08-26 15:14:23 +00:00
if ( ( m_backend - > fbcdrawableinfo [ depth ] . texture_targets & GLX_TEXTURE_2D_BIT_EXT ) & &
2011-07-18 15:55:39 +00:00
( GLTexture : : NPOTTextureSupported ( ) | |
( isPowerOfTwo ( size . width ( ) ) & & isPowerOfTwo ( size . height ( ) ) ) ) ) {
attrs [ 4 ] = GLX_TEXTURE_TARGET_EXT ;
attrs [ 5 ] = GLX_TEXTURE_2D_EXT ;
2012-08-26 15:14:23 +00:00
} else if ( m_backend - > fbcdrawableinfo [ depth ] . texture_targets & GLX_TEXTURE_RECTANGLE_BIT_EXT ) {
2011-07-18 15:55:39 +00:00
attrs [ 4 ] = GLX_TEXTURE_TARGET_EXT ;
attrs [ 5 ] = GLX_TEXTURE_RECTANGLE_EXT ;
2011-01-30 14:34:42 +00:00
}
2011-07-18 15:55:39 +00:00
}
2012-08-26 15:14:23 +00:00
m_glxpixmap = glXCreatePixmap ( display ( ) , m_backend - > fbcdrawableinfo [ depth ] . fbconfig , pix , attrs ) ;
2010-11-21 13:01:39 +00:00
# ifdef CHECK_GL_ERROR
2011-07-18 15:55:39 +00:00
checkGLError ( " TextureLoadTFP1 " ) ;
2010-11-21 13:01:39 +00:00
# endif
2011-07-18 15:55:39 +00:00
findTarget ( ) ;
2012-08-26 15:14:23 +00:00
m_yInverted = m_backend - > fbcdrawableinfo [ depth ] . y_inverted ? true : false ;
m_canUseMipmaps = m_backend - > fbcdrawableinfo [ depth ] . mipmap > 0 ;
q - > setFilter ( m_backend - > fbcdrawableinfo [ depth ] . mipmap > 0 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST ) ;
glBindTexture ( m_target , m_texture ) ;
2011-01-30 10:55:27 +00:00
# ifdef CHECK_GL_ERROR
2011-07-18 15:55:39 +00:00
checkGLError ( " TextureLoadTFP2 " ) ;
2011-01-30 10:55:27 +00:00
# endif
2012-08-26 15:14:23 +00:00
glXBindTexImageEXT ( display ( ) , m_glxpixmap , GLX_FRONT_LEFT_EXT , NULL ) ;
2010-11-21 13:01:39 +00:00
# ifdef CHECK_GL_ERROR
2011-01-30 14:34:42 +00:00
checkGLError ( " TextureLoad0 " ) ;
2010-11-21 13:01:39 +00:00
# endif
2012-01-07 11:12:29 +00:00
unbind ( ) ;
2010-11-21 13:01:39 +00:00
return true ;
2011-01-30 14:34:42 +00:00
}
2010-11-21 13:01:39 +00:00
2012-08-26 15:14:23 +00:00
OpenGLBackend * GlxTexture : : backend ( )
2011-01-30 14:34:42 +00:00
{
2012-08-26 15:14:23 +00:00
return m_backend ;
2012-01-07 11:12:29 +00:00
}
2012-08-26 15:14:23 +00:00
} // namespace
# endif