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"
2017-07-16 15:31:09 +00:00
# include "egl_context_attribute_builder.h"
2016-07-18 14:34:03 +00:00
# include <logging.h>
2015-08-14 14:52:40 +00:00
2017-07-16 15:31:09 +00:00
# include <memory>
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 [ ] = {
2019-04-11 14:39:55 +00:00
EGL_SURFACE_TYPE , 0 ,
2015-08-14 14:52:40 +00:00
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 ;
}
2017-07-31 16:09:15 +00:00
AbstractPlatformContext : : AbstractPlatformContext ( QOpenGLContext * context , EGLDisplay display , EGLConfig config )
2015-08-14 14:52:40 +00:00
: QPlatformOpenGLContext ( )
, 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
QFunctionPointer AbstractPlatformContext : : getProcAddress ( const char * procName )
{
return eglGetProcAddress ( procName ) ;
}
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 " ) ) ;
2018-03-22 09:20:37 +00:00
const bool haveContextPriority = extensions . contains ( QByteArrayLiteral ( " EGL_IMG_context_priority " ) ) ;
2015-11-13 08:45:11 +00:00
2017-07-16 15:31:09 +00:00
std : : vector < std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > > candidates ;
2015-10-30 11:42:59 +00:00
if ( isOpenGLES ( ) ) {
2018-03-22 09:20:37 +00:00
if ( haveCreateContext & & haveRobustness & & haveContextPriority ) {
auto glesRobustPriority = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglOpenGLESContextAttributeBuilder ) ;
glesRobustPriority - > setVersion ( 2 ) ;
glesRobustPriority - > setRobust ( true ) ;
glesRobustPriority - > setHighPriority ( true ) ;
candidates . push_back ( std : : move ( glesRobustPriority ) ) ;
}
2015-11-13 08:45:11 +00:00
if ( haveCreateContext & & haveRobustness ) {
2017-07-16 15:31:09 +00:00
auto glesRobust = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglOpenGLESContextAttributeBuilder ) ;
glesRobust - > setVersion ( 2 ) ;
glesRobust - > setRobust ( true ) ;
candidates . push_back ( std : : move ( glesRobust ) ) ;
2015-11-13 08:45:11 +00:00
}
2018-03-22 09:20:37 +00:00
if ( haveContextPriority ) {
auto glesPriority = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglOpenGLESContextAttributeBuilder ) ;
glesPriority - > setVersion ( 2 ) ;
glesPriority - > setHighPriority ( true ) ;
candidates . push_back ( std : : move ( glesPriority ) ) ;
}
2017-07-16 15:31:09 +00:00
auto gles = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglOpenGLESContextAttributeBuilder ) ;
gles - > setVersion ( 2 ) ;
candidates . push_back ( std : : move ( gles ) ) ;
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 ) {
2018-03-22 09:20:37 +00:00
if ( haveRobustness & & haveContextPriority ) {
auto robustCorePriority = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglContextAttributeBuilder ) ;
robustCorePriority - > setVersion ( m_format . majorVersion ( ) , m_format . minorVersion ( ) ) ;
robustCorePriority - > setRobust ( true ) ;
robustCorePriority - > setForwardCompatible ( true ) ;
if ( m_format . profile ( ) = = QSurfaceFormat : : CoreProfile ) {
robustCorePriority - > setCoreProfile ( true ) ;
} else if ( m_format . profile ( ) = = QSurfaceFormat : : CompatibilityProfile ) {
robustCorePriority - > setCompatibilityProfile ( true ) ;
}
robustCorePriority - > setHighPriority ( true ) ;
candidates . push_back ( std : : move ( robustCorePriority ) ) ;
}
2015-11-13 08:45:11 +00:00
if ( haveRobustness ) {
2017-07-16 15:31:09 +00:00
auto robustCore = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglContextAttributeBuilder ) ;
robustCore - > setVersion ( m_format . majorVersion ( ) , m_format . minorVersion ( ) ) ;
robustCore - > setRobust ( true ) ;
robustCore - > setForwardCompatible ( true ) ;
if ( m_format . profile ( ) = = QSurfaceFormat : : CoreProfile ) {
robustCore - > setCoreProfile ( true ) ;
} else if ( m_format . profile ( ) = = QSurfaceFormat : : CompatibilityProfile ) {
robustCore - > setCompatibilityProfile ( true ) ;
}
candidates . push_back ( std : : move ( robustCore ) ) ;
2015-11-13 08:45:11 +00:00
}
2018-03-22 09:20:37 +00:00
if ( haveContextPriority ) {
auto corePriority = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglContextAttributeBuilder ) ;
corePriority - > setVersion ( m_format . majorVersion ( ) , m_format . minorVersion ( ) ) ;
corePriority - > setForwardCompatible ( true ) ;
if ( m_format . profile ( ) = = QSurfaceFormat : : CoreProfile ) {
corePriority - > setCoreProfile ( true ) ;
} else if ( m_format . profile ( ) = = QSurfaceFormat : : CompatibilityProfile ) {
corePriority - > setCompatibilityProfile ( true ) ;
}
corePriority - > setHighPriority ( true ) ;
candidates . push_back ( std : : move ( corePriority ) ) ;
}
2017-07-16 15:31:09 +00:00
auto core = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglContextAttributeBuilder ) ;
core - > setVersion ( m_format . majorVersion ( ) , m_format . minorVersion ( ) ) ;
core - > setForwardCompatible ( true ) ;
if ( m_format . profile ( ) = = QSurfaceFormat : : CoreProfile ) {
core - > setCoreProfile ( true ) ;
} else if ( m_format . profile ( ) = = QSurfaceFormat : : CompatibilityProfile ) {
core - > setCompatibilityProfile ( true ) ;
2015-11-13 08:45:11 +00:00
}
2017-07-16 15:31:09 +00:00
candidates . push_back ( std : : move ( core ) ) ;
2015-10-30 11:42:59 +00:00
}
2018-03-22 09:20:37 +00:00
if ( haveRobustness & & haveCreateContext & & haveContextPriority ) {
auto robustPriority = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglContextAttributeBuilder ) ;
robustPriority - > setRobust ( true ) ;
robustPriority - > setHighPriority ( true ) ;
candidates . push_back ( std : : move ( robustPriority ) ) ;
}
2017-07-16 15:31:09 +00:00
if ( haveRobustness & & haveCreateContext ) {
auto robust = std : : unique_ptr < AbstractOpenGLContextAttributeBuilder > ( new EglContextAttributeBuilder ) ;
robust - > setRobust ( true ) ;
candidates . push_back ( std : : move ( robust ) ) ;
2015-11-13 08:45:11 +00:00
}
2017-07-16 15:31:09 +00:00
candidates . emplace_back ( new EglContextAttributeBuilder ) ;
}
EGLContext context = EGL_NO_CONTEXT ;
for ( auto it = candidates . begin ( ) ; it ! = candidates . end ( ) ; it + + ) {
const auto attribs = ( * it ) - > build ( ) ;
context = eglCreateContext ( eglDisplay ( ) , config ( ) , shareContext , attribs . data ( ) ) ;
if ( context ! = EGL_NO_CONTEXT ) {
qCDebug ( KWIN_QPA ) < < " Created EGL context with attributes: " < < ( * it ) . get ( ) ;
break ;
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 ;
}
}
}