2015-08-14 14:52:40 +00:00
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project .
Copyright ( C ) 2015 Martin Gräßlin < mgraesslin @ kde . org >
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/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "abstractplatformcontext.h"
# include "integration.h"
2016-07-18 14:34:03 +00:00
# include <logging.h>
2015-08-14 14:52:40 +00:00
namespace KWin
{
namespace QPA
{
2015-10-30 11:42:59 +00:00
static bool isOpenGLES ( )
{
2015-11-02 12:54:53 +00:00
if ( qstrcmp ( qgetenv ( " KWIN_COMPOSE " ) , " O2ES " ) = = 0 ) {
return true ;
}
2015-10-30 11:42:59 +00:00
return QOpenGLContext : : openGLModuleType ( ) = = QOpenGLContext : : LibGLES ;
}
2015-08-14 14:52:40 +00:00
static EGLConfig configFromGLFormat ( EGLDisplay dpy , const QSurfaceFormat & format )
{
# define SIZE( __buffer__ ) format.__buffer__##BufferSize() > 0 ? format.__buffer__##BufferSize() : 0
// not setting samples as QtQuick doesn't need it
const EGLint config_attribs [ ] = {
EGL_SURFACE_TYPE , EGL_WINDOW_BIT ,
EGL_RED_SIZE , SIZE ( red ) ,
EGL_GREEN_SIZE , SIZE ( green ) ,
EGL_BLUE_SIZE , SIZE ( blue ) ,
EGL_ALPHA_SIZE , SIZE ( alpha ) ,
EGL_DEPTH_SIZE , SIZE ( depth ) ,
EGL_STENCIL_SIZE , SIZE ( stencil ) ,
2015-10-30 11:42:59 +00:00
EGL_RENDERABLE_TYPE , isOpenGLES ( ) ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT ,
2015-08-14 14:52:40 +00:00
EGL_NONE ,
} ;
2016-07-19 06:13:22 +00:00
qCDebug ( KWIN_QPA ) < < " Trying to find a format with: rgba/depth/stencil " < < ( SIZE ( red ) ) < < ( SIZE ( green ) ) < < ( SIZE ( blue ) ) < < ( SIZE ( alpha ) ) < < ( SIZE ( depth ) ) < < ( SIZE ( stencil ) ) ;
2015-08-14 14:52:40 +00:00
# undef SIZE
EGLint count ;
EGLConfig configs [ 1024 ] ;
if ( eglChooseConfig ( dpy , config_attribs , configs , 1 , & count ) = = EGL_FALSE ) {
2016-07-18 14:34:03 +00:00
qCWarning ( KWIN_QPA ) < < " eglChooseConfig failed " ;
2015-08-14 14:52:40 +00:00
return 0 ;
}
if ( count ! = 1 ) {
2016-07-18 14:34:03 +00:00
qCWarning ( KWIN_QPA ) < < " eglChooseConfig did not return any configs " ;
2015-08-14 14:52:40 +00:00
return 0 ;
}
return configs [ 0 ] ;
}
static QSurfaceFormat formatFromConfig ( EGLDisplay dpy , EGLConfig config )
{
QSurfaceFormat format ;
EGLint value = 0 ;
# define HELPER(__egl__, __qt__) \
eglGetConfigAttrib ( dpy , config , EGL_ # # __egl__ , & value ) ; \
format . set # # __qt__ ( value ) ; \
value = 0 ;
# define BUFFER_HELPER(__eglColor__, __color__) \
HELPER ( __eglColor__ # # _SIZE , __color__ # # BufferSize )
BUFFER_HELPER ( RED , Red )
BUFFER_HELPER ( GREEN , Green )
BUFFER_HELPER ( BLUE , Blue )
BUFFER_HELPER ( ALPHA , Alpha )
BUFFER_HELPER ( STENCIL , Stencil )
BUFFER_HELPER ( DEPTH , Depth )
# undef BUFFER_HELPER
HELPER ( SAMPLES , Samples )
# undef HELPER
2015-10-30 11:42:59 +00:00
format . setRenderableType ( isOpenGLES ( ) ? QSurfaceFormat : : OpenGLES : QSurfaceFormat : : OpenGL ) ;
2015-08-14 14:52:40 +00:00
format . setStereo ( false ) ;
return format ;
}
2016-07-18 09:17:54 +00:00
AbstractPlatformContext : : AbstractPlatformContext ( QOpenGLContext * context , Integration * integration , EGLDisplay display , EGLConfig config )
2015-08-14 14:52:40 +00:00
: QPlatformOpenGLContext ( )
, m_integration ( integration )
, m_eglDisplay ( display )
2016-07-18 09:17:54 +00:00
, m_config ( config ? config : configFromGLFormat ( m_eglDisplay , context - > format ( ) ) )
2015-08-14 14:52:40 +00:00
, m_format ( formatFromConfig ( m_eglDisplay , m_config ) )
{
}
AbstractPlatformContext : : ~ AbstractPlatformContext ( )
{
if ( m_context ! = EGL_NO_CONTEXT ) {
eglDestroyContext ( m_eglDisplay , m_context ) ;
}
}
void AbstractPlatformContext : : doneCurrent ( )
{
eglMakeCurrent ( m_eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
}
QSurfaceFormat AbstractPlatformContext : : format ( ) const
{
return m_format ;
}
2016-03-09 12:42:24 +00:00
# if (QT_VERSION < QT_VERSION_CHECK(5, 7, 0))
2015-08-14 14:52:40 +00:00
QFunctionPointer AbstractPlatformContext : : getProcAddress ( const QByteArray & procName )
{
return eglGetProcAddress ( procName . constData ( ) ) ;
}
2016-03-09 12:42:24 +00:00
# else
QFunctionPointer AbstractPlatformContext : : getProcAddress ( const char * procName )
{
return eglGetProcAddress ( procName ) ;
}
# endif
2015-08-14 14:52:40 +00:00
bool AbstractPlatformContext : : isValid ( ) const
{
return m_context ! = EGL_NO_CONTEXT ;
}
bool AbstractPlatformContext : : bindApi ( )
{
2015-10-30 11:42:59 +00:00
if ( eglBindAPI ( isOpenGLES ( ) ? EGL_OPENGL_ES_API : EGL_OPENGL_API ) = = EGL_FALSE ) {
2016-07-18 14:34:03 +00:00
qCWarning ( KWIN_QPA ) < < " eglBindAPI failed " ;
2015-08-14 14:52:40 +00:00
return false ;
}
return true ;
}
void AbstractPlatformContext : : createContext ( EGLContext shareContext )
{
2015-11-13 08:45:11 +00:00
const QByteArray eglExtensions = eglQueryString ( eglDisplay ( ) , EGL_EXTENSIONS ) ;
const QList < QByteArray > extensions = eglExtensions . split ( ' ' ) ;
const bool haveRobustness = extensions . contains ( QByteArrayLiteral ( " EGL_EXT_create_context_robustness " ) ) ;
const bool haveCreateContext = extensions . contains ( QByteArrayLiteral ( " EGL_KHR_create_context " ) ) ;
2015-08-14 14:52:40 +00:00
EGLContext context = EGL_NO_CONTEXT ;
2015-10-30 11:42:59 +00:00
if ( isOpenGLES ( ) ) {
2015-11-13 08:45:11 +00:00
if ( haveCreateContext & & haveRobustness ) {
const EGLint context_attribs [ ] = {
EGL_CONTEXT_CLIENT_VERSION , 2 ,
EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT , EGL_TRUE ,
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT , EGL_LOSE_CONTEXT_ON_RESET_EXT ,
EGL_NONE
} ;
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , context_attribs ) ;
}
if ( context = = EGL_NO_CONTEXT ) {
const EGLint context_attribs [ ] = {
EGL_CONTEXT_CLIENT_VERSION , 2 ,
EGL_NONE
} ;
2015-10-30 11:42:59 +00:00
2015-11-13 08:45:11 +00:00
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , context_attribs ) ;
}
2015-10-30 11:42:59 +00:00
} else {
// Try to create a 3.1 core context
2015-11-13 08:45:11 +00:00
if ( m_format . majorVersion ( ) > = 3 & & haveCreateContext ) {
if ( haveRobustness ) {
const int attribs [ ] = {
EGL_CONTEXT_MAJOR_VERSION_KHR , m_format . majorVersion ( ) ,
EGL_CONTEXT_MINOR_VERSION_KHR , m_format . minorVersion ( ) ,
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR , EGL_LOSE_CONTEXT_ON_RESET_KHR ,
EGL_CONTEXT_FLAGS_KHR , EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR ,
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR , m_format . profile ( ) = = QSurfaceFormat : : CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR ,
EGL_NONE
} ;
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , attribs ) ;
}
if ( context = = EGL_NO_CONTEXT ) {
// try without robustness
const EGLint attribs [ ] = {
EGL_CONTEXT_MAJOR_VERSION_KHR , m_format . majorVersion ( ) ,
EGL_CONTEXT_MINOR_VERSION_KHR , m_format . minorVersion ( ) ,
EGL_CONTEXT_FLAGS_KHR , EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR ,
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR , m_format . profile ( ) = = QSurfaceFormat : : CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR ,
EGL_NONE
} ;
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , attribs ) ;
}
2015-10-30 11:42:59 +00:00
}
2015-11-13 08:45:11 +00:00
if ( context = = EGL_NO_CONTEXT & & haveRobustness & & haveCreateContext ) {
const int attribs [ ] = {
EGL_CONTEXT_FLAGS_KHR , EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR ,
EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR , EGL_LOSE_CONTEXT_ON_RESET_KHR ,
EGL_NONE
} ;
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , attribs ) ;
}
2015-10-30 11:42:59 +00:00
if ( context = = EGL_NO_CONTEXT ) {
2015-11-13 08:45:11 +00:00
// and last but not least: try without robustness
const EGLint attribs [ ] = {
EGL_NONE
} ;
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , attribs ) ;
2015-10-30 11:42:59 +00:00
}
2015-08-14 14:52:40 +00:00
}
if ( context = = EGL_NO_CONTEXT ) {
2016-07-18 14:34:03 +00:00
qCWarning ( KWIN_QPA ) < < " Failed to create EGL context " ;
2015-08-14 14:52:40 +00:00
return ;
}
m_context = context ;
}
}
}